From 0fba156ef89f88fd510e0e39c8d8fcb1aa076c40 Mon Sep 17 00:00:00 2001 From: rpm-build Date: Aug 04 2020 14:51:36 +0000 Subject: ostree-2020.4 base --- diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5bc8fb2 --- /dev/null +++ b/COPYING @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 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 library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + 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 Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the 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 a program 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. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + 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, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile 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) 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. + + c) 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. + + d) 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 source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + 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 to +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 Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile-bash.am b/Makefile-bash.am new file mode 100644 index 0000000..b42f6bf --- /dev/null +++ b/Makefile-bash.am @@ -0,0 +1,26 @@ +# Makefile for bash/ +# +# Copyright (C) 2017 Red Hat Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +completionsdir = @BASH_COMPLETIONSDIR@ +dist_completions_DATA = bash/ostree + +# Allow the distcheck install under $prefix test to pass +AM_DISTCHECK_CONFIGURE_FLAGS += BASH_COMPLETIONSDIR='$${datadir}/bash-completion/completions' diff --git a/Makefile-boot.am b/Makefile-boot.am new file mode 100644 index 0000000..b51928f --- /dev/null +++ b/Makefile-boot.am @@ -0,0 +1,75 @@ +# Makefile for boot module +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +if BUILDOPT_DRACUT +# Not using $(libdir) here is intentional, dracut modules go in prefix/lib +dracutmoddir = $(prefix)/lib/dracut/modules.d/98ostree +dracutmod_SCRIPTS = src/boot/dracut/module-setup.sh +endif +if BUILDOPT_DRACUT_CONF +dracutconfdir = $(sysconfdir)/dracut.conf.d +dracutconf_DATA = src/boot/dracut/ostree.conf +endif + +if BUILDOPT_MKINITCPIO +mkinitcpioinstalldir = $(prefix)/lib/initcpio/install +mkinitcpioinstall_SCRIPTS = src/boot/mkinitcpio/ostree + +mkinitcpioconfdir = $(sysconfdir) +mkinitcpioconf_DATA = src/boot/mkinitcpio/ostree-mkinitcpio.conf +endif + +if BUILDOPT_SYSTEMD +systemdsystemunit_DATA = src/boot/ostree-prepare-root.service \ + src/boot/ostree-remount.service \ + src/boot/ostree-finalize-staged.service \ + src/boot/ostree-finalize-staged.path \ + $(NULL) +systemdtmpfilesdir = $(prefix)/lib/tmpfiles.d +dist_systemdtmpfiles_DATA = src/boot/ostree-tmpfiles.conf + +# Allow the distcheck install under $prefix test to pass +AM_DISTCHECK_CONFIGURE_FLAGS += --with-systemdsystemunitdir='$${libdir}/systemd/system' +endif + +if !BUILDOPT_BUILTIN_GRUB2_MKCONFIG +# We're using the system grub2-mkconfig generator +pkglibexec_SCRIPTS += src/boot/grub2/grub2-15_ostree +install-grub2-config-hook: + mkdir -p $(DESTDIR)$(grub2configdir) + ln -sf $(pkglibexecdir)/grub2-15_ostree $(DESTDIR)$(grub2configdir)/15_ostree +grub2configdir = $(sysconfdir)/grub.d +INSTALL_DATA_HOOKS += install-grub2-config-hook +else +# We're using our internal generator +ostree_boot_SCRIPTS += src/boot/grub2/ostree-grub-generator +endif + +EXTRA_DIST += src/boot/dracut/module-setup.sh \ + src/boot/dracut/ostree.conf \ + src/boot/mkinitcpio/ostree \ + src/boot/ostree-prepare-root.service \ + src/boot/ostree-finalize-staged.path \ + src/boot/ostree-remount.service \ + src/boot/ostree-finalize-staged.service \ + src/boot/grub2/grub2-15_ostree \ + src/boot/grub2/ostree-grub-generator \ + $(NULL) diff --git a/Makefile-decls.am b/Makefile-decls.am new file mode 100644 index 0000000..086ee13 --- /dev/null +++ b/Makefile-decls.am @@ -0,0 +1,61 @@ +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Common variables +AM_CPPFLAGS = +AM_CFLAGS = +AM_DISTCHECK_CONFIGURE_FLAGS = +SUBDIRS = +NULL = +BUILT_SOURCES = +MANPAGES = +CLEANFILES = +EXTRA_DIST = +bin_PROGRAMS = +sbin_PROGRAMS = +bin_SCRIPTS = +lib_LTLIBRARIES = +libexec_PROGRAMS = +pkglibexec_PROGRAMS = +pkglibexec_SCRIPTS = +noinst_LTLIBRARIES = +noinst_PROGRAMS = +privlibdir = $(pkglibdir) +privlib_LTLIBRARIES = +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = +INTROSPECTION_GIRS = +girdir = $(datadir)/gir-1.0 +gir_DATA = +typelibdir = $(libdir)/girepository-1.0 +typelib_DATA = +gsettings_SCHEMAS = +ostree_bootdir = $(prefix)/lib/ostree +ostree_boot_SCRIPTS = +ostree_boot_PROGRAMS = + +# This initializes some more variables +include $(top_srcdir)/buildutil/glib-tap.mk + +# This is a special facility to chain together hooks easily +INSTALL_DATA_HOOKS = +install-data-hook: $(INSTALL_DATA_HOOKS) + +ALL_LOCAL_RULES = +all-local: $(ALL_LOCAL_RULES) diff --git a/Makefile-libostree-defines.am b/Makefile-libostree-defines.am new file mode 100644 index 0000000..43e0928 --- /dev/null +++ b/Makefile-libostree-defines.am @@ -0,0 +1,55 @@ +# Shared variables between toplevel Makefile.am and doc/Makefile.am +# ...since gtk-doc forces use of recursive make =( +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +libostree_public_headers = \ + src/libostree/ostree.h \ + src/libostree/ostree-async-progress.h \ + src/libostree/ostree-autocleanups.h \ + src/libostree/ostree-core.h \ + src/libostree/ostree-dummy-enumtypes.h \ + src/libostree/ostree-mutable-tree.h \ + src/libostree/ostree-repo.h \ + src/libostree/ostree-types.h \ + src/libostree/ostree-repo-file.h \ + src/libostree/ostree-diff.h \ + src/libostree/ostree-gpg-verify-result.h \ + src/libostree/ostree-sepolicy.h \ + src/libostree/ostree-sysroot.h \ + src/libostree/ostree-sysroot-upgrader.h \ + src/libostree/ostree-deployment.h \ + src/libostree/ostree-bootconfig-parser.h \ + src/libostree/ostree-repo-deprecated.h \ + src/libostree/ostree-ref.h \ + src/libostree/ostree-remote.h \ + src/libostree/ostree-repo-finder.h \ + src/libostree/ostree-repo-finder-avahi.h \ + src/libostree/ostree-repo-finder-config.h \ + src/libostree/ostree-repo-finder-mount.h \ + src/libostree/ostree-repo-finder-override.h \ + src/libostree/ostree-kernel-args.h \ + src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-ed25519.h \ + $(NULL) + +# This one is generated via configure.ac, and the gtk-doc +# code hence needs to look in the builddir. +libostree_public_built_headers = src/libostree/ostree-version.h diff --git a/Makefile-libostree.am b/Makefile-libostree.am new file mode 100644 index 0000000..96b9249 --- /dev/null +++ b/Makefile-libostree.am @@ -0,0 +1,316 @@ +# Makefile for C source code +# +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +include Makefile-libostree-defines.am + + +if ENABLE_RUST +bupsplitpath = @abs_top_builddir@/target/@RUST_TARGET_SUBDIR@/libbupsplit_rs.a +BUPSPLIT_RUST_SRCS = rust/src/bupsplit.rs +EXTRA_DIST += $(BUPSPLIT_RUST_SRCS) +$(bupsplitpath): Makefile $(BUPSPLIT_RUST_SRCS) + cd $(top_srcdir)/rust && CARGO_TARGET_DIR=@abs_top_builddir@/target cargo build --verbose $(CARGO_RELEASE_ARGS) +else +bupsplitpath = libbupsplit.la +noinst_LTLIBRARIES += libbupsplit.la +libbupsplit_la_SOURCES = src/libostree/bupsplit.h src/libostree/bupsplit.c +endif # ENABLE_RUST + +lib_LTLIBRARIES += libostree-1.la + +libostreeincludedir = $(includedir)/ostree-1 +libostreeinclude_HEADERS = $(libostree_public_headers) $(libostree_public_built_headers) + +ENUM_TYPES = $(NULL) +ENUM_TYPES += $(srcdir)/src/libostree/ostree-fetcher.h + +# TODO: GLIB_CHECK_VERSION > 2.5x: use --output instead of mv (see https://github.com/ostreedev/ostree/pull/1329) +src/libostree/ostree-enumtypes.h: src/libostree/ostree-enumtypes.h.template $(ENUM_TYPES) + $(AM_V_GEN) $(GLIB_MKENUMS) \ + --template $< \ + $(ENUM_TYPES) > $@.tmp && mv $@.tmp $@ + +src/libostree/ostree-enumtypes.c: src/libostree/ostree-enumtypes.c.template src/libostree/ostree-enumtypes.h $(ENUM_TYPES) + $(AM_V_GEN) $(GLIB_MKENUMS) \ + --template $< \ + $(ENUM_TYPES) > $@.tmp && mv $@.tmp $@ + +nodist_libostree_1_la_SOURCES = \ + src/libostree/ostree-enumtypes.h \ + src/libostree/ostree-enumtypes.c \ + $(NULL) + +BUILT_SOURCES += $(nodist_libostree_1_la_SOURCES) + +CLEANFILES += $(BUILT_SOURCES) + +libostree_1_la_SOURCES = \ + src/libostree/ostree-async-progress.c \ + src/libostree/ostree-cmdprivate.h \ + src/libostree/ostree-cmdprivate.c \ + src/libostree/ostree-core-private.h \ + src/libostree/ostree-core.c \ + src/libostree/ostree-dummy-enumtypes.c \ + src/libostree/ostree-checksum-input-stream.c \ + src/libostree/ostree-checksum-input-stream.h \ + src/libostree/ostree-chain-input-stream.c \ + src/libostree/ostree-chain-input-stream.h \ + src/libostree/ostree-lzma-common.c \ + src/libostree/ostree-lzma-common.h \ + src/libostree/ostree-lzma-compressor.c \ + src/libostree/ostree-lzma-compressor.h \ + src/libostree/ostree-lzma-decompressor.c \ + src/libostree/ostree-lzma-decompressor.h \ + src/libostree/ostree-rollsum.h \ + src/libostree/ostree-rollsum.c \ + src/libostree/ostree-varint.h \ + src/libostree/ostree-varint.c \ + src/libostree/ostree-linuxfsutil.h \ + src/libostree/ostree-linuxfsutil.c \ + src/libostree/ostree-diff.c \ + src/libostree/ostree-mutable-tree.c \ + src/libostree/ostree-ref.c \ + src/libostree/ostree-remote.c \ + src/libostree/ostree-remote-private.h \ + src/libostree/ostree-repo.c \ + src/libostree/ostree-repo-checkout.c \ + src/libostree/ostree-repo-commit.c \ + src/libostree/ostree-repo-pull.c \ + src/libostree/ostree-repo-pull-private.h \ + src/libostree/ostree-repo-pull-verify.c \ + src/libostree/ostree-repo-libarchive.c \ + src/libostree/ostree-repo-prune.c \ + src/libostree/ostree-repo-refs.c \ + src/libostree/ostree-repo-traverse.c \ + src/libostree/ostree-repo-private.h \ + src/libostree/ostree-repo-file.c \ + src/libostree/ostree-repo-file-enumerator.c \ + src/libostree/ostree-repo-file-enumerator.h \ + src/libostree/ostree-sepolicy.c \ + src/libostree/ostree-sepolicy-private.h \ + src/libostree/ostree-sysroot-private.h \ + src/libostree/ostree-sysroot.c \ + src/libostree/ostree-sysroot-cleanup.c \ + src/libostree/ostree-sysroot-deploy.c \ + src/libostree/ostree-sysroot-upgrader.c \ + src/libostree/ostree-impl-system-generator.c \ + src/libostree/ostree-bootconfig-parser.c \ + src/libostree/ostree-deployment.c \ + src/libostree/ostree-bootloader.h \ + src/libostree/ostree-bootloader.c \ + src/libostree/ostree-bootloader-grub2.h \ + src/libostree/ostree-bootloader-grub2.c \ + src/libostree/ostree-bootloader-zipl.h \ + src/libostree/ostree-bootloader-zipl.c \ + src/libostree/ostree-bootloader-syslinux.h \ + src/libostree/ostree-bootloader-syslinux.c \ + src/libostree/ostree-bootloader-uboot.h \ + src/libostree/ostree-bootloader-uboot.c \ + src/libostree/ostree-repo-static-delta-core.c \ + src/libostree/ostree-repo-static-delta-processing.c \ + src/libostree/ostree-repo-static-delta-compilation.c \ + src/libostree/ostree-repo-static-delta-compilation-analysis.c \ + src/libostree/ostree-repo-static-delta-private.h \ + src/libostree/ostree-autocleanups.h \ + src/libostree/ostree-bloom.c \ + src/libostree/ostree-bloom-private.h \ + src/libostree/ostree-repo-finder.c \ + src/libostree/ostree-repo-finder-avahi.c \ + src/libostree/ostree-repo-finder-config.c \ + src/libostree/ostree-repo-finder-mount.c \ + src/libostree/ostree-repo-finder-override.c \ + src/libostree/ostree-kernel-args.h \ + src/libostree/ostree-kernel-args.c \ + $(NULL) +if USE_LIBARCHIVE +libostree_1_la_SOURCES += src/libostree/ostree-libarchive-input-stream.h \ + src/libostree/ostree-libarchive-input-stream.c \ + src/libostree/ostree-libarchive-private.h \ + $(NULL) +endif +if HAVE_LIBSOUP_CLIENT_CERTS +libostree_1_la_SOURCES += \ + src/libostree/ostree-tls-cert-interaction.c \ + src/libostree/ostree-tls-cert-interaction.h \ + $(NULL) +endif +libostree_experimental_headers = \ + $(NULL) +if !ENABLE_EXPERIMENTAL_API +libostree_1_la_SOURCES += $(libostree_experimental_headers) +else # if ENABLE_EXPERIMENTAL_API +libostree_1_la_SOURCES += \ + $(NULL) +endif + +if USE_AVAHI +libostree_1_la_SOURCES += \ + src/libostree/ostree-repo-finder-avahi-parser.c \ + src/libostree/ostree-repo-finder-avahi-private.h \ + $(NULL) +endif # USE_AVAHI + +if USE_GPGME +libostree_1_la_SOURCES += \ + src/libostree/ostree-gpg-verifier.c \ + src/libostree/ostree-gpg-verifier.h \ + src/libostree/ostree-gpg-verify-result.c \ + src/libostree/ostree-gpg-verify-result-private.h \ + $(NULL) +else +libostree_1_la_SOURCES += \ + src/libostree/ostree-gpg-verify-result-dummy.c \ + $(NULL) +endif # USE_GPGME + +symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym +if BUILDOPT_IS_DEVEL_BUILD +symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym +endif +# http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html +wl_versionscript_arg = -Wl,--version-script= +EXTRA_DIST += \ + $(top_srcdir)/src/libostree/libostree-devel.sym \ + $(top_srcdir)/src/libostree/libostree-released.sym \ + $(NULL) + +libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/bsdiff -I$(srcdir)/libglnx -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree -I$(builddir)/src/libostree \ + $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) $(OT_DEP_LZMA_CFLAGS) $(OT_DEP_ZLIB_CFLAGS) $(OT_DEP_CRYPTO_CFLAGS) \ + -fvisibility=hidden '-D_OSTREE_PUBLIC=__attribute__((visibility("default"))) extern' +libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions $(addprefix $(wl_versionscript_arg),$(symbol_files)) +libostree_1_la_LIBADD = libotutil.la libglnx.la libbsdiff.la $(OT_INTERNAL_GIO_UNIX_LIBS) $(OT_INTERNAL_GPGME_LIBS) \ + $(OT_DEP_LZMA_LIBS) $(OT_DEP_ZLIB_LIBS) $(OT_DEP_CRYPTO_LIBS) +# Some change between rust-1.21.0-1.fc27 and rust-1.22.1-1.fc27.x86_64 +if ENABLE_RUST +libostree_1_la_LIBADD += -ldl +endif +libostree_1_la_LIBADD += $(bupsplitpath) +EXTRA_libostree_1_la_DEPENDENCIES = $(symbol_files) + +if USE_LIBARCHIVE +libostree_1_la_CFLAGS += $(OT_DEP_LIBARCHIVE_CFLAGS) +libostree_1_la_LIBADD += $(OT_DEP_LIBARCHIVE_LIBS) +endif + +if USE_AVAHI +libostree_1_la_CFLAGS += $(OT_DEP_AVAHI_CFLAGS) +libostree_1_la_LIBADD += $(OT_DEP_AVAHI_LIBS) +endif + +if BUILDOPT_SYSTEMD +libostree_1_la_CFLAGS += $(LIBSYSTEMD_CFLAGS) +libostree_1_la_LIBADD += $(LIBSYSTEMD_LIBS) +endif + +if USE_CURL_OR_SOUP +libostree_1_la_SOURCES += \ + src/libostree/ostree-fetcher.h \ + src/libostree/ostree-fetcher-util.h \ + src/libostree/ostree-fetcher-util.c \ + src/libostree/ostree-fetcher-uri.c \ + src/libostree/ostree-metalink.h \ + src/libostree/ostree-metalink.c \ + $(NULL) +endif + +if USE_CURL +libostree_1_la_SOURCES += src/libostree/ostree-fetcher-curl.c \ + src/libostree/ostree-soup-uri.h src/libostree/ostree-soup-uri.c \ + src/libostree/ostree-soup-form.c \ + $(NULL) +libostree_1_la_CFLAGS += $(OT_DEP_CURL_CFLAGS) +libostree_1_la_LIBADD += $(OT_DEP_CURL_LIBS) +else +if USE_LIBSOUP +libostree_1_la_SOURCES += src/libostree/ostree-fetcher-soup.c +libostree_1_la_CFLAGS += $(OT_INTERNAL_SOUP_CFLAGS) +libostree_1_la_LIBADD += $(OT_INTERNAL_SOUP_LIBS) +else +if USE_AVAHI +libostree_1_la_SOURCES += src/libostree/ostree-soup-uri.h \ + src/libostree/ostree-soup-uri.c \ + src/libostree/ostree-soup-form.c \ + $(NULL) +endif +endif +endif + +if USE_LIBMOUNT +libostree_1_la_CFLAGS += $(OT_DEP_LIBMOUNT_CFLAGS) +libostree_1_la_LIBADD += $(OT_DEP_LIBMOUNT_LIBS) +endif + +if USE_SELINUX +libostree_1_la_CFLAGS += $(OT_DEP_SELINUX_CFLAGS) +libostree_1_la_LIBADD += $(OT_DEP_SELINUX_LIBS) +endif + +libostree_1_la_SOURCES += \ + src/libostree/ostree-sign.c \ + src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-dummy.c \ + src/libostree/ostree-sign-dummy.h \ + src/libostree/ostree-sign-ed25519.c \ + src/libostree/ostree-sign-ed25519.h \ + $(NULL) + +if USE_LIBSODIUM +libostree_1_la_CFLAGS += $(OT_DEP_LIBSODIUM_CFLAGS) +libostree_1_la_LIBADD += $(OT_DEP_LIBSODIUM_LIBS) +endif # USE_LIBSODIUM + +# XXX: work around clang being passed -fstack-clash-protection which it doesn't understand +# See: https://bugzilla.redhat.com/show_bug.cgi?id=1672012 +INTROSPECTION_SCANNER_ENV = CC=gcc + +if BUILDOPT_INTROSPECTION +OSTree-1.0.gir: libostree-1.la Makefile +OSTree_1_0_gir_EXPORT_PACKAGES = ostree-1 +OSTree_1_0_gir_INCLUDES = Gio-2.0 +OSTree_1_0_gir_CFLAGS = $(libostree_1_la_CFLAGS) +if ENABLE_EXPERIMENTAL_API +# When compiling this is set via config.h, but g-ir-scanner can't use that +OSTree_1_0_gir_CFLAGS += -DOSTREE_ENABLE_EXPERIMENTAL_API=1 +endif +OSTree_1_0_gir_LIBS = libostree-1.la +OSTree_1_0_gir_SCANNERFLAGS = --warn-all --identifier-prefix=Ostree --symbol-prefix=ostree $(GI_SCANNERFLAGS) +OSTree_1_0_gir_FILES = $(libostreeinclude_HEADERS) $(filter-out %-private.h %/ostree-soup-uri.h $(libostree_experimental_headers),$(libostree_1_la_SOURCES)) +INTROSPECTION_GIRS += OSTree-1.0.gir +gir_DATA += OSTree-1.0.gir +typelib_DATA += OSTree-1.0.typelib + +CLEANFILES += $(gir_DATA) $(typelib_DATA) +endif + +pkgconfig_DATA += src/libostree/ostree-1.pc + +gpgreadme_DATA = src/libostree/README-gpg +gpgreadmedir = $(datadir)/ostree/trusted.gpg.d +EXTRA_DIST += src/libostree/README-gpg src/libostree/bupsplit.h \ + src/libostree/ostree-enumtypes.h.template \ + src/libostree/ostree-enumtypes.c.template \ + src/libostree/ostree-deployment-private.h \ + src/libostree/ostree-repo-deprecated.h \ + src/libostree/ostree-version.h + +install-mkdir-remotes-d-hook: + mkdir -p $(DESTDIR)$(sysconfdir)/ostree/remotes.d +INSTALL_DATA_HOOKS += install-mkdir-remotes-d-hook diff --git a/Makefile-man.am b/Makefile-man.am new file mode 100644 index 0000000..718e773 --- /dev/null +++ b/Makefile-man.am @@ -0,0 +1,82 @@ +# Makefile for man/ +# +# Copyright (C) 2016 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +if ENABLE_MAN + +man1_files = ostree.1 ostree-admin-cleanup.1 \ +ostree-admin-config-diff.1 ostree-admin-deploy.1 \ +ostree-admin-init-fs.1 ostree-admin-instutil.1 ostree-admin-os-init.1 \ +ostree-admin-status.1 ostree-admin-set-origin.1 ostree-admin-switch.1 \ +ostree-admin-undeploy.1 ostree-admin-upgrade.1 ostree-admin-unlock.1 \ +ostree-admin-pin.1 \ +ostree-admin.1 ostree-cat.1 ostree-checkout.1 ostree-checksum.1 \ +ostree-commit.1 ostree-create-usb.1 ostree-export.1 \ +ostree-config.1 ostree-diff.1 ostree-find-remotes.1 ostree-fsck.1 \ +ostree-init.1 ostree-log.1 ostree-ls.1 ostree-prune.1 ostree-pull-local.1 \ +ostree-pull.1 ostree-refs.1 ostree-remote.1 ostree-reset.1 \ +ostree-rev-parse.1 ostree-show.1 ostree-sign.1 ostree-summary.1 \ +ostree-static-delta.1 +if USE_LIBSOUP +man1_files += ostree-trivial-httpd.1 +else +# We still want to distribute the source, even if we are not building it +EXTRA_DIST += man/ostree-trivial-httpd.xml +endif + +if BUILDOPT_FUSE +man1_files += rofiles-fuse.1 +endif + +if USE_GPGME +man1_files += ostree-gpg-sign.1 +endif + +man5_files = ostree.repo.5 ostree.repo-config.5 + +man1_MANS = $(addprefix man/,$(man1_files)) +man5_MANS = $(addprefix man/,$(man5_files)) + +EXTRA_DIST += $(man1_MANS:.1=.xml) $(man5_MANS:.5=.xml) + +XSLT_STYLESHEET = http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl + +XSLTPROC_FLAGS = \ + --nonet \ + --stringparam man.output.quietly 1 \ + --stringparam funcsynopsis.style ansi \ + --stringparam man.th.extra1.suppress 1 \ + --stringparam man.authors.section.enabled 0 \ + --stringparam man.copyright.section.enabled 0 + +XSLTPROC_MAN = $(XSLTPROC) $(XSLTPROC_FLAGS) + +%.1: %.xml + $(AM_V_GEN) $(XSLTPROC_MAN) --output $@ $(XSLT_STYLESHEET) $< + +%.5: %.xml + $(AM_V_GEN) $(XSLTPROC_MAN) --output $@ $(XSLT_STYLESHEET) $< + +CLEANFILES += \ + $(man1_MANS) \ + $(man5_MANS) \ + $(NULL) + +endif diff --git a/Makefile-ostree.am b/Makefile-ostree.am new file mode 100644 index 0000000..e576764 --- /dev/null +++ b/Makefile-ostree.am @@ -0,0 +1,169 @@ +# Makefile for C source code +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +bin_PROGRAMS += ostree + +ostree_SOURCES = src/ostree/main.c \ + src/ostree/ot-builtin-admin.c \ + src/ostree/ot-builtins.h \ + src/ostree/ot-builtin-cat.c \ + src/ostree/ot-builtin-config.c \ + src/ostree/ot-builtin-checkout.c \ + src/ostree/ot-builtin-checksum.c \ + src/ostree/ot-builtin-commit.c \ + src/ostree/ot-builtin-create-usb.c \ + src/ostree/ot-builtin-diff.c \ + src/ostree/ot-builtin-export.c \ + src/ostree/ot-builtin-find-remotes.c \ + src/ostree/ot-builtin-fsck.c \ + src/ostree/ot-builtin-init.c \ + src/ostree/ot-builtin-pull-local.c \ + src/ostree/ot-builtin-log.c \ + src/ostree/ot-builtin-ls.c \ + src/ostree/ot-builtin-prune.c \ + src/ostree/ot-builtin-refs.c \ + src/ostree/ot-builtin-remote.c \ + src/ostree/ot-builtin-reset.c \ + src/ostree/ot-builtin-rev-parse.c \ + src/ostree/ot-builtin-sign.c \ + src/ostree/ot-builtin-summary.c \ + src/ostree/ot-builtin-show.c \ + src/ostree/ot-builtin-static-delta.c \ + src/ostree/ot-main.h \ + src/ostree/ot-main.c \ + src/ostree/ot-dump.h \ + src/ostree/ot-dump.c \ + src/ostree/ot-editor.c \ + src/ostree/ot-editor.h \ + src/ostree/parse-datetime.h \ + $(NULL) + +nodist_ostree_SOURCES = \ + src/ostree/parse-datetime.c \ + $(NULL) + +if ENABLE_EXPERIMENTAL_API +ostree_SOURCES += \ + $(NULL) +endif + +if USE_GPGME +ostree_SOURCES += \ + src/ostree/ot-builtin-gpg-sign.c \ + $(NULL) +endif + +# Admin subcommand +ostree_SOURCES += \ + src/ostree/ot-admin-builtin-init-fs.c \ + src/ostree/ot-admin-builtin-diff.c \ + src/ostree/ot-admin-builtin-deploy.c \ + src/ostree/ot-admin-builtin-finalize-staged.c \ + src/ostree/ot-admin-builtin-undeploy.c \ + src/ostree/ot-admin-builtin-instutil.c \ + src/ostree/ot-admin-builtin-cleanup.c \ + src/ostree/ot-admin-builtin-os-init.c \ + src/ostree/ot-admin-builtin-set-origin.c \ + src/ostree/ot-admin-builtin-status.c \ + src/ostree/ot-admin-builtin-switch.c \ + src/ostree/ot-admin-builtin-pin.c \ + src/ostree/ot-admin-builtin-upgrade.c \ + src/ostree/ot-admin-builtin-unlock.c \ + src/ostree/ot-admin-builtins.h \ + src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c \ + src/ostree/ot-admin-instutil-builtin-set-kargs.c \ + src/ostree/ot-admin-instutil-builtin-grub2-generate.c \ + src/ostree/ot-admin-instutil-builtins.h \ + src/ostree/ot-admin-functions.h \ + src/ostree/ot-admin-functions.c \ + $(NULL) + +# Remote subcommand +ostree_SOURCES += \ + src/ostree/ot-remote-builtins.h \ + src/ostree/ot-remote-builtin-add.c \ + src/ostree/ot-remote-builtin-delete.c \ + src/ostree/ot-remote-builtin-list.c \ + src/ostree/ot-remote-builtin-show-url.c \ + src/ostree/ot-remote-builtin-refs.c \ + src/ostree/ot-remote-builtin-summary.c \ + $(NULL) + +if USE_GPGME +ostree_SOURCES += \ + src/ostree/ot-remote-builtin-gpg-import.c \ + $(NULL) +endif + +if USE_CURL_OR_SOUP +ostree_SOURCES += src/ostree/ot-remote-builtin-add-cookie.c \ + src/ostree/ot-remote-builtin-delete-cookie.c \ + src/ostree/ot-remote-builtin-list-cookies.c \ + src/ostree/ot-remote-cookie-util.h \ + src/ostree/ot-remote-cookie-util.c \ + $(NULL) +endif + +src/ostree/parse-datetime.c: src/ostree/parse-datetime.y Makefile + mkdir -p src/ostree/ + $(AM_V_GEN) $(YACC) $< -o $@ + +EXTRA_DIST += src/ostree/parse-datetime.y +CLEANFILES += src/ostree/parse-datetime.c + +ostree_bin_shared_cflags = $(AM_CFLAGS) -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree \ + -I$(builddir)/src/libostree -I$(srcdir)/src/ostree -I$(srcdir)/libglnx $(OT_INTERNAL_GIO_UNIX_CFLAGS) \ + -DPKGLIBEXECDIR=\"$(pkglibexecdir)\" +ostree_bin_shared_ldadd = $(AM_LDFLAGS) libglnx.la libotutil.la libostree-1.la \ + $(OT_INTERNAL_GIO_UNIX_LIBS) + +ostree_CFLAGS = $(ostree_bin_shared_cflags) +ostree_LDADD = $(ostree_bin_shared_ldadd) libbsdiff.la $(LIBSYSTEMD_LIBS) + + +if USE_CURL_OR_SOUP +ostree_SOURCES += src/ostree/ot-builtin-pull.c +endif + +if USE_LIBSOUP +# Eventually once we stop things from using this, we should support disabling this +ostree_SOURCES += src/ostree/ot-builtin-trivial-httpd.c +pkglibexec_PROGRAMS += ostree-trivial-httpd +ostree_trivial_httpd_SOURCES = src/ostree/ostree-trivial-httpd.c +ostree_trivial_httpd_CFLAGS = $(ostree_bin_shared_cflags) $(OT_INTERNAL_SOUP_CFLAGS) +ostree_trivial_httpd_LDADD = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_SOUP_LIBS) + +if !USE_CURL +# This is necessary for the cookie jar bits +ostree_CFLAGS += $(OT_INTERNAL_SOUP_CFLAGS) +ostree_LDADD += $(OT_INTERNAL_SOUP_LIBS) +endif +endif + +if USE_LIBARCHIVE +ostree_CFLAGS += $(OT_DEP_LIBARCHIVE_CFLAGS) +ostree_LDADD += $(OT_DEP_LIBARCHIVE_LIBS) +endif + +if USE_LIBSODIUM +ostree_CFLAGS += $(OT_DEP_LIBSODIUM_CFLAGS) +ostree_LDADD += $(OT_DEP_LIBSODIUM_LIBS) +endif # USE_LIBSODIUM diff --git a/Makefile-otutil.am b/Makefile-otutil.am new file mode 100644 index 0000000..e8901b5 --- /dev/null +++ b/Makefile-otutil.am @@ -0,0 +1,56 @@ +# Makefile for C source code +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +noinst_LTLIBRARIES += libotutil.la + +libotutil_la_SOURCES = \ + src/libotutil/ot-checksum-utils.c \ + src/libotutil/ot-checksum-utils.h \ + src/libotutil/ot-checksum-instream.c \ + src/libotutil/ot-checksum-instream.h \ + src/libotutil/ot-fs-utils.c \ + src/libotutil/ot-fs-utils.h \ + src/libotutil/ot-keyfile-utils.c \ + src/libotutil/ot-keyfile-utils.h \ + src/libotutil/ot-opt-utils.c \ + src/libotutil/ot-opt-utils.h \ + src/libotutil/ot-unix-utils.c \ + src/libotutil/ot-unix-utils.h \ + src/libotutil/ot-variant-utils.c \ + src/libotutil/ot-variant-utils.h \ + src/libotutil/ot-variant-builder.c \ + src/libotutil/ot-variant-builder.h \ + src/libotutil/ot-gio-utils.c \ + src/libotutil/ot-gio-utils.h \ + src/libotutil/otutil.h \ + src/libotutil/ot-tool-util.c \ + src/libotutil/ot-tool-util.h \ + $(NULL) + +if USE_GPGME +libotutil_la_SOURCES += \ + src/libotutil/ot-gpg-utils.c \ + src/libotutil/ot-gpg-utils.h \ + $(NULL) +endif + +libotutil_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libotutil -DLOCALEDIR=\"$(datadir)/locale\" $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) $(LIBSYSTEMD_CFLAGS) +libotutil_la_LIBADD = $(OT_INTERNAL_GIO_UNIX_LIBS) $(OT_INTERNAL_GPGME_LIBS) $(LIBSYSTEMD_LIBS) diff --git a/Makefile-switchroot.am b/Makefile-switchroot.am new file mode 100644 index 0000000..ad370eb --- /dev/null +++ b/Makefile-switchroot.am @@ -0,0 +1,82 @@ +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +if BUILDOPT_SYSTEMD +ostree_boot_PROGRAMS += ostree-remount +else +# It is built anyway as a side-effect of having the symlink in tests/, +# and if we declare it here, it gets cleaned up properly +check_PROGRAMS += ostree-remount +endif + +ostree_prepare_root_SOURCES = \ + src/switchroot/ostree-mount-util.h \ + src/switchroot/ostree-prepare-root.c \ + $(NULL) +ostree_prepare_root_CPPFLAGS = $(AM_CPPFLAGS) + +if BUILDOPT_USE_STATIC_COMPILER +# ostree-prepare-root can be used as init in a system without a populated /lib. +# To support this use case we need to link statically as we will be unable to +# locate libc.so at run time if it's not installed in /lib. +# +# We support building ostree-prepare-root with a different compiler to the rest +# of ostree so we can use musl rather than glibc. This reduces the size of the +# executable significantly: from ~700K -> ~30K. We have to use _SCRIPTS here +# to get autotools to install this as an executable but without generating rules +# to make it itself which we have specified manually. See +# https://lists.gnu.org/archive/html/help-gnu-utils/2007-01/msg00007.html +ostree_boot_SCRIPTS += ostree-prepare-root + +ostree-prepare-root : $(ostree_prepare_root_SOURCES) + $(STATIC_COMPILER) -o $@ -static $(top_srcdir)/src/switchroot/ostree-prepare-root.c $(ostree_prepare_root_CPPFLAGS) $(AM_CFLAGS) $(DEFAULT_INCLUDES) -DOSTREE_PREPARE_ROOT_STATIC=1 +else +ostree_boot_PROGRAMS += ostree-prepare-root +ostree_prepare_root_CFLAGS = $(AM_CFLAGS) -Isrc/switchroot +endif + +ostree_remount_SOURCES = \ + src/switchroot/ostree-mount-util.h \ + src/switchroot/ostree-remount.c \ + $(NULL) +ostree_remount_CPPFLAGS = $(AM_CPPFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -Isrc/switchroot -I$(srcdir)/libglnx +ostree_remount_LDADD = $(AM_LDFLAGS) $(OT_INTERNAL_GIO_UNIX_LIBS) libglnx.la + +if BUILDOPT_SYSTEMD +ostree_prepare_root_CPPFLAGS += -DHAVE_SYSTEMD=1 +ostree_prepare_root_LDADD = $(AM_LDFLAGS) $(LIBSYSTEMD_LIBS) +endif + +# This is the "new mode" of using a generator for /var; see +# https://github.com/ostreedev/ostree/issues/855 +if BUILDOPT_SYSTEMD_AND_LIBMOUNT +ostree_prepare_root_CPPFLAGS += -DHAVE_SYSTEMD_AND_LIBMOUNT=1 +ostree_remount_CPPFLAGS += -DHAVE_SYSTEMD_AND_LIBMOUNT=1 + +systemdsystemgenerator_PROGRAMS = ostree-system-generator +GITIGNOREFILES += $(systemdsystemgenerator_PROGRAMS) +ostree_system_generator_SOURCES = src/switchroot/ostree-mount-util.h \ + src/switchroot/ostree-system-generator.c +ostree_system_generator_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libostree +ostree_system_generator_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) +ostree_system_generator_LDADD = $(AM_LDFLAGS) libglnx.la libostree-1.la $(OT_INTERNAL_GIO_UNIX_LIBS) + +# Allow the distcheck install under $prefix test to pass +AM_DISTCHECK_CONFIGURE_FLAGS += --with-systemdsystemgeneratordir='$${libdir}/systemd/system-generators' +endif diff --git a/Makefile-tests.am b/Makefile-tests.am new file mode 100644 index 0000000..a417937 --- /dev/null +++ b/Makefile-tests.am @@ -0,0 +1,467 @@ +# Makefile for tests code +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +EXTRA_DIST += \ + buildutil/tap-driver.sh \ + buildutil/tap-test \ + tests/glib.supp \ + tests/ostree.supp \ + $(NULL) + +# We should probably consider flipping the default for DEBUG. Also, +# include the builddir in $PATH so we find our just-built ostree +# binary. +AM_TESTS_ENVIRONMENT += OT_TESTS_DEBUG=1 \ + OSTREE_UNINSTALLED_SRCDIR=$(abs_top_srcdir) \ + OSTREE_UNINSTALLED=$(abs_top_builddir) \ + G_DEBUG=fatal-warnings \ + GI_TYPELIB_PATH=$$(cd $(top_builddir) && pwd)$${GI_TYPELIB_PATH:+:$$GI_TYPELIB_PATH} \ + LD_LIBRARY_PATH=$$(cd $(top_builddir)/.libs && pwd)$${LD_LIBRARY_PATH:+:$${LD_LIBRARY_PATH}} \ + PATH=$$(cd $(top_builddir)/tests && pwd):$${PATH} \ + OSTREE_FEATURES="$(OSTREE_FEATURES)" \ + PYTHONUNBUFFERED=1 \ + $(NULL) +if BUILDOPT_ASAN +AM_TESTS_ENVIRONMENT += OT_SKIP_READDIR_RAND=1 G_SLICE=always-malloc +endif + +uninstalled_test_data = tests/ostree-symlink-stamp tests/ostree-prepare-root-symlink-stamp \ + tests/ostree-remount-symlink-stamp + +dist_uninstalled_test_scripts = tests/test-symbols.sh tests/coccinelle.sh + +# This logic implements ENABLE_INSTALLED_TESTS_EXCLUSIVE; see below. +# The goal here if installed tests are enabled, we explicitly make the +# tests *only* run installed, to avoid having to run them twice in CI. +# This overrides the glib-tap.mk emphasis on doing both, if we'd +# used e.g. `dist_test_scripts`. +dist_test_scripts = $(NULL) +test_programs = \ + tests/test-bloom \ + tests/test-repo-finder-config \ + tests/test-repo-finder-mount \ + $(NULL) +_installed_or_uninstalled_test_scripts = \ + tests/test-basic.sh \ + tests/test-basic-user.sh \ + tests/test-basic-user-only.sh \ + tests/test-basic-root.sh \ + tests/test-pull-subpath.sh \ + tests/test-archivez.sh \ + tests/test-remote-add.sh \ + tests/test-remote-headers.sh \ + tests/test-commit-sign.sh \ + tests/test-export.sh \ + tests/test-help.sh \ + tests/test-libarchive.sh \ + tests/test-parent.sh \ + tests/test-pull-bare.sh \ + tests/test-pull-bareuser.sh \ + tests/test-pull-bareuseronly.sh \ + tests/test-pull2-bareuseronly.sh \ + tests/test-pull-commit-only.sh \ + tests/test-pull-depth.sh \ + tests/test-pull-mirror-summary.sh \ + tests/test-pull-large-metadata.sh \ + tests/test-pull-metalink.sh \ + tests/test-pull-summary-sigs.sh \ + tests/test-pull-resume.sh \ + tests/test-pull-basicauth.sh \ + tests/test-pull-repeated.sh \ + tests/test-pull-sizes.sh \ + tests/test-pull-untrusted.sh \ + tests/test-pull-override-url.sh \ + tests/test-pull-localcache.sh \ + tests/test-local-pull.sh \ + tests/test-local-pull-depth.sh \ + tests/test-admin-upgrade-unconfigured.sh \ + tests/test-admin-upgrade-endoflife.sh \ + tests/test-admin-upgrade-systemd-update.sh \ + tests/test-admin-deploy-syslinux.sh \ + tests/test-admin-deploy-2.sh \ + tests/test-admin-deploy-karg.sh \ + tests/test-admin-deploy-switch.sh \ + tests/test-admin-deploy-etcmerge-cornercases.sh \ + tests/test-admin-deploy-uboot.sh \ + tests/test-admin-deploy-grub2.sh \ + tests/test-admin-deploy-nomerge.sh \ + tests/test-admin-deploy-none.sh \ + tests/test-admin-deploy-bootid-gc.sh \ + tests/test-admin-instutil-set-kargs.sh \ + tests/test-admin-upgrade-not-backwards.sh \ + tests/test-admin-pull-deploy-commit.sh \ + tests/test-admin-pull-deploy-split.sh \ + tests/test-admin-locking.sh \ + tests/test-admin-deploy-clean.sh \ + tests/test-reset-nonlinear.sh \ + tests/test-oldstyle-partial.sh \ + tests/test-delta.sh \ + tests/test-xattrs.sh \ + tests/test-auto-summary.sh \ + tests/test-prune.sh \ + tests/test-concurrency.py \ + tests/test-refs.sh \ + tests/test-demo-buildsystem.sh \ + tests/test-switchroot.sh \ + tests/test-pull-contenturl.sh \ + tests/test-pull-mirrorlist.sh \ + tests/test-summary-update.sh \ + tests/test-summary-view.sh \ + tests/test-no-initramfs.sh \ + tests/test-create-usb.sh \ + tests/test-find-remotes.sh \ + tests/test-fsck-collections.sh \ + tests/test-fsck-delete.sh \ + tests/test-init-collections.sh \ + tests/test-prune-collections.sh \ + tests/test-refs-collections.sh \ + tests/test-remote-add-collections.sh \ + tests/test-repo-finder-mount-integration.sh \ + tests/test-summary-collections.sh \ + tests/test-pull-collections.sh \ + tests/test-config.sh \ + tests/test-signed-commit.sh \ + tests/test-signed-pull.sh \ + tests/test-pre-signed-pull.sh \ + tests/test-signed-pull-summary.sh \ + $(NULL) + +if USE_GPGME +_installed_or_uninstalled_test_scripts += \ + tests/test-remote-gpg-import.sh \ + tests/test-gpg-signed-commit.sh \ + tests/test-admin-gpg.sh \ + $(NULL) +endif + +experimental_test_scripts = \ + $(NULL) +test_extra_programs = \ + tests/get-byte-order \ + tests/repo-finder-mount \ + $(NULL) + +tests_get_byte_order_SOURCES = tests/get-byte-order.c +tests_get_byte_order_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS) +tests_get_byte_order_LDADD = $(GLIB_LIBS) + +tests_repo_finder_mount_SOURCES = tests/repo-finder-mount.c +tests_repo_finder_mount_CFLAGS = $(common_tests_cflags) +tests_repo_finder_mount_LDADD = $(common_tests_ldadd) libostreetest.la + +if ENABLE_EXPERIMENTAL_API +_installed_or_uninstalled_test_scripts += $(experimental_test_scripts) +else +EXTRA_DIST += $(experimental_test_scripts) +endif + +if BUILDOPT_FUSE +_installed_or_uninstalled_test_scripts += tests/test-rofiles-fuse.sh +uninstalled_test_data += tests/rofiles-fuse-symlink-stamp +else +EXTRA_DIST += tests/test-rofiles-fuse.sh +endif + +if USE_LIBSOUP +_installed_or_uninstalled_test_scripts += tests/test-remote-cookies.sh +endif + +# These call into gjs scripts +js_tests = tests/test-corruption.sh tests/test-pull-corruption.sh +if BUILDOPT_GJS +_installed_or_uninstalled_test_scripts += $(js_tests) +else +EXTRA_DIST += $(js_tests) +endif + +dist_installed_test_data = tests/archive-test.sh \ + tests/pull-test.sh \ + tests/pull-test2.sh \ + tests/admin-test.sh \ + tests/basic-test.sh \ + tests/pre-endian-deltas-repo-big.tar.xz \ + tests/pre-endian-deltas-repo-little.tar.xz \ + tests/fah-deltadata-old.tar.xz \ + tests/fah-deltadata-new.tar.xz \ + tests/ostree-path-traverse.tar.gz \ + tests/pre-signed-pull-data.tar.gz \ + tests/libtest-core.sh \ + $(NULL) + +EXTRA_DIST += tests/libtest.sh + +dist_test_extra_scripts = \ + tests/bootloader-entries-crosscheck.py \ + tests/corrupt-repo-ref.js \ + tests/ostree-grub-generator \ + $(NULL) + +if USE_GPGME +# We can't use nobase_ as we need to strip off the tests/, can't +# use plain installed_ as we do need the gpghome/ prefix. +if ENABLE_INSTALLED_TESTS +gpginsttestdir = $(installed_testdir)/gpghome +dist_gpginsttest_DATA = tests/gpghome/secring.gpg \ + tests/gpghome/pubring.gpg \ + tests/gpghome/trustdb.gpg \ + tests/gpghome/key1.asc \ + tests/gpghome/key2.asc \ + tests/gpghome/key3.asc +gpginsttest_trusteddir = $(installed_testdir)/gpghome/trusted +dist_gpginsttest_trusted_DATA = tests/gpghome/trusted/pubring.gpg +gpginsttest_revocdir = $(installed_testdir)/gpghome/revocations +dist_gpginsttest_revoc_DATA = \ + tests/gpghome/revocations/key1.rev \ + tests/gpghome/revocations/key2.rev \ + tests/gpghome/revocations/key3.rev \ + $(NULL) + +gpgvinsttestdir = $(installed_testdir)/gpg-verify-data +dist_gpgvinsttest_DATA = $(addprefix tests/gpg-verify-data/, \ + gpg.conf lgpl2 lgpl2.sig lgpl2.sig0 lgpl2.sig1 lgpl2.sig2 lgpl2.sig3 \ + lgpl2.sig4 pubring.gpg secring.gpg trustdb.gpg) +endif +endif + +js_installed_tests = \ + tests/test-core.js \ + tests/test-remotes-config-dir.js \ + tests/test-sizes.js \ + tests/test-sysroot.js \ + $(NULL) + +if BUILDOPT_GJS +_installed_or_uninstalled_test_scripts += $(js_installed_tests) +else +EXTRA_DIST += $(js_installed_tests) +endif + +test_ltlibraries = libreaddir-rand.la +libreaddir_rand_la_SOURCES = tests/readdir-rand.c +libreaddir_rand_la_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) +libreaddir_rand_la_LIBADD = \ + -ldl \ + $(OT_INTERNAL_GIO_UNIX_LIBS) \ + $(NULL) +libreaddir_rand_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version +if !ENABLE_INSTALLED_TESTS +libreaddir_rand_la_LDFLAGS += -rpath $(abs_builddir) +endif + +_installed_or_uninstalled_test_programs = tests/test-varint tests/test-ot-unix-utils tests/test-bsdiff tests/test-mutable-tree \ + tests/test-keyfile-utils tests/test-ot-opt-utils tests/test-ot-tool-util \ + tests/test-checksum tests/test-lzma tests/test-rollsum \ + tests/test-basic-c tests/test-sysroot-c tests/test-pull-c tests/test-repo tests/test-include-ostree-h tests/test-kargs + +if USE_GPGME +_installed_or_uninstalled_test_programs += \ + tests/test-gpg-verify-result \ + $(NULL) +endif + +if USE_AVAHI +test_programs += tests/test-repo-finder-avahi +endif + +# An interactive tool +noinst_PROGRAMS += tests/test-rollsum-cli + +if USE_LIBARCHIVE +_installed_or_uninstalled_test_programs += tests/test-libarchive-import +endif + +common_tests_cflags = $(ostree_bin_shared_cflags) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/libglnx +common_tests_ldadd = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_GIO_UNIX_LIBS) + +noinst_LTLIBRARIES += libostreetest.la +libostreetest_la_SOURCES = tests/libostreetest.c tests/test-mock-gio.c tests/test-mock-gio.h +libostreetest_la_CFLAGS = $(common_tests_cflags) -I $(srcdir)/tests +libostreetest_la_LIBADD = $(common_tests_ldadd) + +TESTS_CFLAGS = $(common_tests_cflags) +TESTS_LDADD = $(common_tests_ldadd) libostreetest.la + +tests_test_rollsum_cli_SOURCES = src/libostree/ostree-rollsum.c tests/test-rollsum-cli.c +tests_test_rollsum_cli_CFLAGS = $(TESTS_CFLAGS) $(OT_DEP_ZLIB_CFLAGS) +tests_test_rollsum_cli_LDADD = $(bupsplitpath) $(TESTS_LDADD) $(OT_DEP_ZLIB_LIBS) + +tests_test_rollsum_SOURCES = src/libostree/ostree-rollsum.c tests/test-rollsum.c +tests_test_rollsum_CFLAGS = $(TESTS_CFLAGS) $(OT_DEP_ZLIB_CFLAGS) +tests_test_rollsum_LDADD = $(bupsplitpath) $(TESTS_LDADD) $(OT_DEP_ZLIB_LIBS) + +tests_test_bloom_SOURCES = src/libostree/ostree-bloom.c tests/test-bloom.c +tests_test_bloom_CFLAGS = $(TESTS_CFLAGS) +tests_test_bloom_LDADD = $(TESTS_LDADD) + +tests_test_include_ostree_h_SOURCES = tests/test-include-ostree-h.c +# Don't use TESTS_CFLAGS so we test if the public header can be included by external programs +tests_test_include_ostree_h_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/src/libostree -I$(builddir)/src/libostree +# Don't define OSTREE_COMPILATION so that we're compiling as if it's an external program +tests_test_include_ostree_h_CPPFLAGS = $(AM_CPPFLAGS) -UOSTREE_COMPILATION +tests_test_include_ostree_h_LDADD = $(TESTS_LDADD) + +if USE_AVAHI +tests_test_repo_finder_avahi_SOURCES = src/libostree/ostree-repo-finder-avahi-parser.c tests/test-repo-finder-avahi.c +tests_test_repo_finder_avahi_CFLAGS = $(TESTS_CFLAGS) +tests_test_repo_finder_avahi_LDADD = $(TESTS_LDADD) +endif + +tests_test_kargs_SOURCES = src/libostree/ostree-kernel-args.c tests/test-kargs.c +tests_test_kargs_CFLAGS = $(TESTS_CFLAGS) +tests_test_kargs_LDADD = $(TESTS_LDADD) + +tests_test_repo_finder_config_SOURCES = tests/test-repo-finder-config.c +tests_test_repo_finder_config_CFLAGS = $(TESTS_CFLAGS) +tests_test_repo_finder_config_LDADD = $(TESTS_LDADD) + +tests_test_repo_finder_mount_SOURCES = tests/test-repo-finder-mount.c +tests_test_repo_finder_mount_CFLAGS = $(TESTS_CFLAGS) +tests_test_repo_finder_mount_LDADD = $(TESTS_LDADD) + +tests_test_mutable_tree_CFLAGS = $(TESTS_CFLAGS) +tests_test_mutable_tree_LDADD = $(TESTS_LDADD) + +tests_test_basic_c_CFLAGS = $(TESTS_CFLAGS) +tests_test_basic_c_LDADD = $(TESTS_LDADD) + +tests_test_sysroot_c_CFLAGS = $(TESTS_CFLAGS) +tests_test_sysroot_c_LDADD = $(TESTS_LDADD) + +tests_test_pull_c_CFLAGS = $(TESTS_CFLAGS) +tests_test_pull_c_LDADD = $(TESTS_LDADD) + +tests_test_repo_CFLAGS = $(TESTS_CFLAGS) +tests_test_repo_LDADD = $(TESTS_LDADD) + +tests_test_ot_unix_utils_CFLAGS = $(TESTS_CFLAGS) +tests_test_ot_unix_utils_LDADD = $(TESTS_LDADD) + +tests_test_varint_SOURCES = src/libostree/ostree-varint.c tests/test-varint.c +tests_test_varint_CFLAGS = $(TESTS_CFLAGS) +tests_test_varint_LDADD = $(TESTS_LDADD) + +tests_test_bsdiff_CFLAGS = $(TESTS_CFLAGS) +tests_test_bsdiff_LDADD = libbsdiff.la $(TESTS_LDADD) + +tests_test_checksum_SOURCES = \ + src/libostree/ostree-core.c \ + src/libostree/ostree-varint.c \ + tests/test-checksum.c +tests_test_checksum_CFLAGS = $(TESTS_CFLAGS) $(libglnx_cflags) +tests_test_checksum_LDADD = $(TESTS_LDADD) + +tests_test_libarchive_import_SOURCES = tests/test-libarchive-import.c +tests_test_libarchive_import_CFLAGS = $(TESTS_CFLAGS) $(libglnx_cflags) $(OT_DEP_LIBARCHIVE_CFLAGS) +tests_test_libarchive_import_LDADD = $(TESTS_LDADD) $(OT_DEP_LIBARCHIVE_LIBS) + +tests_test_keyfile_utils_CFLAGS = $(TESTS_CFLAGS) +tests_test_keyfile_utils_LDADD = $(TESTS_LDADD) + +tests_test_ot_opt_utils_CFLAGS = $(TESTS_CFLAGS) +tests_test_ot_opt_utils_LDADD = $(TESTS_LDADD) + +tests_test_ot_tool_util_CFLAGS = $(TESTS_CFLAGS) +tests_test_ot_tool_util_LDADD = $(TESTS_LDADD) + +tests_test_lzma_SOURCES = src/libostree/ostree-lzma-common.c src/libostree/ostree-lzma-compressor.c \ + src/libostree/ostree-lzma-decompressor.c tests/test-lzma.c +tests_test_lzma_CFLAGS = $(TESTS_CFLAGS) $(OT_DEP_LZMA_CFLAGS) +tests_test_lzma_LDADD = $(TESTS_LDADD) $(OT_DEP_LZMA_LIBS) + +if USE_GPGME +tests_test_gpg_verify_result_SOURCES = \ + src/libostree/ostree-gpg-verify-result-private.h \ + tests/test-gpg-verify-result.c +tests_test_gpg_verify_result_CFLAGS = $(TESTS_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) +tests_test_gpg_verify_result_LDADD = $(TESTS_LDADD) $(OT_INTERNAL_GPGME_LIBS) + +EXTRA_DIST += \ + tests/gpg-verify-data/README.md \ + $(NULL) +endif + +EXTRA_DIST += \ + tests/libostreetest.h \ + tests/libtest.sh \ + $(NULL) + +tests/libreaddir-rand.so: Makefile + mkdir -p tests/ + $(AM_V_GEN) ln -fns ../.libs/libreaddir-rand.so tests/ +ALL_LOCAL_RULES += tests/libreaddir-rand.so +CLEANFILES += tests/libreaddir-rand.so tests/ostree-symlink-stamp \ + tests/ostree-prepare-root-symlink-stamp tests/ostree-remount-symlink-stamp \ + tests/rofiles-fuse-symlink-stamp tests/ostree +CLEANFILES += tests/ostree-prepare-root tests/ostree-remount tests/rofiles-fuse + +tests/%-symlink-stamp: % Makefile + $(AM_V_GEN) set -e; \ + lt_bin=`cd $(top_builddir) && ./libtool --mode=execute echo $*`; \ + if test "$${lt_bin}" = "$*"; then \ + real_bin=$(abs_top_builddir)/$*; \ + else \ + real_bin="$${lt_bin}"; \ + fi; \ + ln -sf "$${real_bin}" tests/$*; \ + touch $@ + +# See above comment on binding the tests to be either installed or not. +if ENABLE_INSTALLED_TESTS_EXCLUSIVE +dist_installed_test_scripts = $(_installed_or_uninstalled_test_scripts) +installed_test_programs = $(_installed_or_uninstalled_test_programs) +check-local: + echo "NOTE: Exclusive installed tests are enabled; to run them, make install, then: gnome-desktop-testing-runner -p 0 libostree/" +else +dist_test_scripts += $(_installed_or_uninstalled_test_scripts) +test_programs += $(_installed_or_uninstalled_test_programs) +endif + +if !USE_LIBSOUP +no-soup-for-you-warning: + @echo "WARNING: $(PACKAGE) was built without libsoup, which is currently" 1>&2 + @echo "WARNING: required for many unit tests." 1>&2 + sleep 10 +check: no-soup-for-you-warning +endif + +# Unfortunately the glib test data APIs don't actually handle +# non-recursive Automake, so we change our code to canonically look +# for tests/ which is just a symlink when installed. +if ENABLE_INSTALLED_TESTS +install-installed-tests-extra: + if test -L $(DESTDIR)$(installed_testdir)/tests; then \ + rm $(DESTDIR)$(installed_testdir)/tests; \ + fi + ln -s . $(DESTDIR)$(installed_testdir)/tests +if BUILDOPT_ASAN + sed -e 's,^BUILT_WITH_ASAN=.*,BUILT_WITH_ASAN=1,' < $(srcdir)/tests/libtest.sh > $(DESTDIR)$(installed_testdir)/tests/libtest.sh +else + install -m 0644 $(srcdir)/tests/libtest.sh $(DESTDIR)$(installed_testdir)/tests/libtest.sh +endif +INSTALL_DATA_HOOKS += install-installed-tests-extra +endif + +# Just forward these +build-kola-tests: + $(MAKE) -C tests/kola + +install-kola-tests: + $(MAKE) -C tests/kola install diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..cd04a05 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,170 @@ +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +include Makefile-decls.am + +shortened_sysconfdir = $$(echo "$(sysconfdir)" | sed -e 's|^$(prefix)||' -e 's|^/||') + +OSTREE_GITREV=$(shell cd $(srcdir) && if command -v git >/dev/null 2>&1 && test -d .git; then git describe --abbrev=42 --tags --always HEAD; fi) + +ACLOCAL_AMFLAGS = -I buildutil -I libglnx ${ACLOCAL_FLAGS} +AM_CPPFLAGS += -DDATADIR='"$(datadir)"' -DLIBEXECDIR='"$(libexecdir)"' \ + -DLOCALEDIR=\"$(datadir)/locale\" -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DTARGET_PREFIX='"$(prefix)"' -DSHORTENED_SYSCONFDIR=\"$(shortened_sysconfdir)\" \ + -DOSTREE_FEATURES='"$(OSTREE_FEATURES)"' \ + -DOSTREE_COMPILATION \ + -DG_LOG_DOMAIN=\"OSTree\" \ + -DOSTREE_GITREV='"$(OSTREE_GITREV)"' \ + -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_40 '-DGLIB_VERSION_MAX_ALLOWED=G_ENCODE_VERSION(2,50)' \ + -DSOUP_VERSION_MIN_REQUIRED=SOUP_VERSION_2_40 '-DSOUP_VERSION_MAX_ALLOWED=G_ENCODE_VERSION(2,48)' +# For strict aliasing, see https://bugzilla.gnome.org/show_bug.cgi?id=791622 +AM_CFLAGS += -std=gnu99 -fno-strict-aliasing $(WARN_CFLAGS) +AM_DISTCHECK_CONFIGURE_FLAGS += \ + --enable-gtk-doc \ + --enable-man \ + --disable-maintainer-mode \ + $(NULL) + +GITIGNOREFILES = aclocal.m4 build-aux/ buildutil/*.m4 config.h.in gtk-doc.make + +SUBDIRS += . + +if ENABLE_GTK_DOC +SUBDIRS += apidoc +endif + +EXTRA_DIST += autogen.sh COPYING README.md + +OT_INTERNAL_GIO_UNIX_CFLAGS = $(OT_DEP_GIO_UNIX_CFLAGS) +OT_INTERNAL_GIO_UNIX_LIBS = $(OT_DEP_GIO_UNIX_LIBS) +OT_INTERNAL_SOUP_CFLAGS = $(OT_DEP_SOUP_CFLAGS) +OT_INTERNAL_SOUP_LIBS = $(OT_DEP_SOUP_LIBS) + +# This canonicalizes the PKG_CHECK_MODULES or AM_PATH_GPGME results +if USE_GPGME +OT_INTERNAL_GPGME_CFLAGS = $(OT_DEP_GPGME_CFLAGS) $(GPGME_PTHREAD_CFLAGS) +OT_INTERNAL_GPGME_LIBS = $(OT_DEP_GPGME_LIBS) $(GPGME_PTHREAD_LIBS) +endif + +if BUILDOPT_INTROSPECTION +include $(INTROSPECTION_MAKEFILE) +GIRS = +TYPELIBS = $(GIRS:.gir=.typelib) +endif + +# These bits based on gnome:librsvg/Makefile.am +if ENABLE_RUST +if RUST_DEBUG +CARGO_RELEASE_ARGS= +else +CARGO_RELEASE_ARGS=--release +endif + +check-local: + cd $(srcdir)/rust && CARGO_TARGET_DIR=$(abs_top_builddir)/target cargo test + +clean-local: + cd $(srcdir)/rust && CARGO_TARGET_DIR=$(abs_top_builddir)/target cargo clean + +dist-hook: + (cd $(distdir)/rust && \ + cp $(abs_top_srcdir)/rust/Cargo.lock . && \ + cargo vendor -q && \ + mkdir .cargo && \ + cp cargo-vendor-config .cargo/config) + +EXTRA_DIST += $(srcdir)/rust/Cargo.toml $(srcdir)/rust/cargo-vendor-config +endif # end ENABLE_RUST + +libglnx_srcpath := $(srcdir)/libglnx +libglnx_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(libglnx_srcpath)" +libglnx_libs := $(OT_DEP_GIO_UNIX_LIBS) +# See also autogen.sh and https://github.com/ostreedev/ostree/pull/1274/ +# +# v2017.12 didn't include test-libglnx-shutil.c, but if you re-run +# autogen.sh (as we do in Debian, to update the Autotools build system) +# it will try to build it. +$(srcdir)/libglnx/Makefile-libglnx.am.inc: $(srcdir)/libglnx/Makefile-libglnx.am + sed -e 's,$$(libglnx_srcpath),libglnx,g' < $< > $@ +include libglnx/Makefile-libglnx.am.inc +EXTRA_DIST += libglnx/Makefile-libglnx.am +noinst_LTLIBRARIES += libglnx.la + +libbsdiff_srcpath := $(srcdir)/bsdiff + +libbsdiff_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(bsdiff_srcpath)" +libbsdiff_libs := $(OT_DEP_GIO_UNIX_LIBS) +# See the comment for the similar libglnx bit above +$(srcdir)/bsdiff/Makefile-bsdiff.am.inc: $(srcdir)/bsdiff/Makefile-bsdiff.am + sed -e 's,$$(libbsdiff_srcpath),bsdiff,g' < $< > $@ +include bsdiff/Makefile-bsdiff.am.inc +EXTRA_DIST += bsdiff/Makefile-bsdiff.am +noinst_LTLIBRARIES += libbsdiff.la + +include Makefile-otutil.am +include Makefile-libostree.am +include Makefile-ostree.am +include Makefile-switchroot.am +if BUILDOPT_FUSE +include src/rofiles-fuse/Makefile-inc.am +endif +include Makefile-tests.am +include Makefile-boot.am +include Makefile-man.am +include Makefile-bash.am + +release-tag: + cd $(srcdir) && git $(srcdir) tag -m "Release $(VERSION)" v$(VERSION) + +embed_dependency=tar -C $(srcdir) --append --exclude='.git/*' --transform="s,^embedded-dependencies/,ostree-embeddeps-$${GITVERSION}/embedded-dependencies/," --file=$${TARFILE_TMP} + +git_version_rpm = $$(cd $(srcdir) && git describe | sed -e 's,-,\.,g' -e 's,^v,,') + +release-tarball-embedded: + set -x; \ + GITVERSION=$(git_version_rpm); export GITVERSION; \ + TARFILE_TMP=ostree-embeddeps-$${GITVERSION}.tar.tmp; \ + REV=$$(git rev-parse HEAD); \ + echo "Archiving ostree at $${REV}"; \ + (cd $(srcdir); git archive --format=tar --prefix=ostree-embeddeps-$${GITVERSION}/ $${REV}) > $${TARFILE_TMP}; \ + (cd $$(git rev-parse --show-toplevel); git submodule status) | while read line; do \ + rev=$$(echo $$line | cut -f 1 -d ' '); path=$$(echo $$line | cut -f 2 -d ' '); \ + echo "Archiving $${path} at $${rev}"; \ + (cd $(srcdir)/$$path; git archive --format=tar --prefix=ostree-embeddeps-$${GITVERSION}/$$path/ $${rev}) > submodule.tar; \ + tar -A -f $${TARFILE_TMP} submodule.tar; \ + rm submodule.tar; \ + done; \ + echo "Archiving glib"; \ + $(embed_dependency) embedded-dependencies/glib; \ + echo "Archiving libsoup"; \ + $(embed_dependency) embedded-dependencies/libsoup; \ + mv ostree-embeddeps-$${GITVERSION}.tar{.tmp,}; \ + gzip -f ostree-embeddeps-$${GITVERSION}.tar + +# `make dist` + `make`; explicitly not the other +# parts of distcheck like `make uninstall` since +# we don't care about that. +dist-then-build: dist + rm $(distdir) -rf && tar -xf $(distdir).tar.xz + cd $(distdir) && mkdir _build && cd _build && \ + ../configure --prefix=/usr --libdir=/usr/lib --sysconfdir=/etc && \ + $(MAKE) && make install DESTDIR=$$(pwd)/_install && \ + rm -rf $(distdir) + +-include $(top_srcdir)/git.mk diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..541e5d4 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,9777 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# GLIB - Library of useful C routines + +# Copyright (C) 2015 Colin Walters +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Copyright (C) 2015 Giuseppe Scrivano +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted providing that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +# Makefile for C source code +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Makefile for C source code +# +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Shared variables between toplevel Makefile.am and doc/Makefile.am +# ...since gtk-doc forces use of recursive make =( +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Makefile for C source code +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Copyright (C) 2016 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Makefile for tests code +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Makefile for boot module +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Makefile for man/ +# +# Copyright (C) 2016 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Makefile for bash/ +# +# Copyright (C) 2017 Red Hat Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + + + + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = ostree$(EXEEXT) $(am__EXEEXT_1) +sbin_PROGRAMS = +libexec_PROGRAMS = +pkglibexec_PROGRAMS = $(am__EXEEXT_19) +noinst_PROGRAMS = $(am__EXEEXT_16) tests/test-rollsum-cli$(EXEEXT) +ostree_boot_PROGRAMS = $(am__EXEEXT_17) $(am__EXEEXT_18) +TESTS = $(am__EXEEXT_8) $(am__EXEEXT_27) \ + $(dist_uninstalled_test_scripts) $(am__EXEEXT_13) +installed_test_PROGRAMS = $(am__EXEEXT_15) +check_PROGRAMS = $(am__EXEEXT_12) $(am__EXEEXT_13) $(am__EXEEXT_14) +@ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__append_1 = $(all_test_ltlibs) +@ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__append_2 = $(all_test_programs) +@ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__append_3 = $(all_test_scripts) +@ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__append_4 = $(all_test_data) +@ENABLE_ALWAYS_BUILD_TESTS_FALSE@am__append_5 = $(all_test_ltlibs) +@ENABLE_ALWAYS_BUILD_TESTS_FALSE@am__append_6 = $(all_test_programs) +@ENABLE_ALWAYS_BUILD_TESTS_FALSE@am__append_7 = $(all_test_scripts) +@ENABLE_ALWAYS_BUILD_TESTS_FALSE@am__append_8 = $(all_test_data) +@ENABLE_INSTALLED_TESTS_TRUE@am__append_9 = $(test_programs) $(installed_test_programs) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(test_extra_programs) $(installed_test_extra_programs) + +@ENABLE_INSTALLED_TESTS_TRUE@am__append_10 = $(test_scripts) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(installed_test_scripts) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(test_extra_scripts) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(test_installed_extra_scripts) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(dist_test_scripts) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(dist_test_extra_scripts) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(dist_installed_test_scripts) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(dist_installed_test_extra_scripts) +@ENABLE_INSTALLED_TESTS_TRUE@am__append_11 = $(test_data) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(installed_test_data) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(dist_test_data) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(dist_installed_test_data) +@ENABLE_INSTALLED_TESTS_TRUE@am__append_12 = $(test_ltlibraries) $(installed_test_ltlibraries) +@ENABLE_INSTALLED_TESTS_TRUE@am__append_13 = $(installed_test_meta_DATA) +@ENABLE_GTK_DOC_TRUE@am__append_14 = apidoc +@ENABLE_RUST_TRUE@am__append_15 = $(srcdir)/rust/Cargo.toml $(srcdir)/rust/cargo-vendor-config +@USE_GPGME_TRUE@am__append_16 = \ +@USE_GPGME_TRUE@ src/libotutil/ot-gpg-utils.c \ +@USE_GPGME_TRUE@ src/libotutil/ot-gpg-utils.h \ +@USE_GPGME_TRUE@ $(NULL) + +@ENABLE_RUST_TRUE@am__append_17 = $(BUPSPLIT_RUST_SRCS) +@ENABLE_RUST_FALSE@am__append_18 = libbupsplit.la +@USE_LIBARCHIVE_TRUE@am__append_19 = src/libostree/ostree-libarchive-input-stream.h \ +@USE_LIBARCHIVE_TRUE@ src/libostree/ostree-libarchive-input-stream.c \ +@USE_LIBARCHIVE_TRUE@ src/libostree/ostree-libarchive-private.h \ +@USE_LIBARCHIVE_TRUE@ $(NULL) + +@HAVE_LIBSOUP_CLIENT_CERTS_TRUE@am__append_20 = \ +@HAVE_LIBSOUP_CLIENT_CERTS_TRUE@ src/libostree/ostree-tls-cert-interaction.c \ +@HAVE_LIBSOUP_CLIENT_CERTS_TRUE@ src/libostree/ostree-tls-cert-interaction.h \ +@HAVE_LIBSOUP_CLIENT_CERTS_TRUE@ $(NULL) + +@ENABLE_EXPERIMENTAL_API_FALSE@am__append_21 = $(libostree_experimental_headers) +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_22 = \ +@ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL) + +@USE_AVAHI_TRUE@am__append_23 = \ +@USE_AVAHI_TRUE@ src/libostree/ostree-repo-finder-avahi-parser.c \ +@USE_AVAHI_TRUE@ src/libostree/ostree-repo-finder-avahi-private.h \ +@USE_AVAHI_TRUE@ $(NULL) + +@USE_GPGME_TRUE@am__append_24 = \ +@USE_GPGME_TRUE@ src/libostree/ostree-gpg-verifier.c \ +@USE_GPGME_TRUE@ src/libostree/ostree-gpg-verifier.h \ +@USE_GPGME_TRUE@ src/libostree/ostree-gpg-verify-result.c \ +@USE_GPGME_TRUE@ src/libostree/ostree-gpg-verify-result-private.h \ +@USE_GPGME_TRUE@ $(NULL) + +@USE_GPGME_FALSE@am__append_25 = \ +@USE_GPGME_FALSE@ src/libostree/ostree-gpg-verify-result-dummy.c \ +@USE_GPGME_FALSE@ $(NULL) + +@BUILDOPT_IS_DEVEL_BUILD_TRUE@am__append_26 = $(top_srcdir)/src/libostree/libostree-devel.sym +# Some change between rust-1.21.0-1.fc27 and rust-1.22.1-1.fc27.x86_64 +@ENABLE_RUST_TRUE@am__append_27 = -ldl +@USE_LIBARCHIVE_TRUE@am__append_28 = $(OT_DEP_LIBARCHIVE_CFLAGS) +@USE_LIBARCHIVE_TRUE@am__append_29 = $(OT_DEP_LIBARCHIVE_LIBS) +@USE_AVAHI_TRUE@am__append_30 = $(OT_DEP_AVAHI_CFLAGS) +@USE_AVAHI_TRUE@am__append_31 = $(OT_DEP_AVAHI_LIBS) +@BUILDOPT_SYSTEMD_TRUE@am__append_32 = $(LIBSYSTEMD_CFLAGS) +@BUILDOPT_SYSTEMD_TRUE@am__append_33 = $(LIBSYSTEMD_LIBS) +@USE_CURL_OR_SOUP_TRUE@am__append_34 = \ +@USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-fetcher.h \ +@USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-fetcher-util.h \ +@USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-fetcher-util.c \ +@USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-fetcher-uri.c \ +@USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-metalink.h \ +@USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-metalink.c \ +@USE_CURL_OR_SOUP_TRUE@ $(NULL) + +@USE_CURL_TRUE@am__append_35 = src/libostree/ostree-fetcher-curl.c \ +@USE_CURL_TRUE@ src/libostree/ostree-soup-uri.h src/libostree/ostree-soup-uri.c \ +@USE_CURL_TRUE@ src/libostree/ostree-soup-form.c \ +@USE_CURL_TRUE@ $(NULL) + +@USE_CURL_TRUE@am__append_36 = $(OT_DEP_CURL_CFLAGS) +@USE_CURL_TRUE@am__append_37 = $(OT_DEP_CURL_LIBS) +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_38 = src/libostree/ostree-fetcher-soup.c +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_39 = $(OT_INTERNAL_SOUP_CFLAGS) +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_40 = $(OT_INTERNAL_SOUP_LIBS) +@USE_AVAHI_TRUE@@USE_CURL_FALSE@@USE_LIBSOUP_FALSE@am__append_41 = src/libostree/ostree-soup-uri.h \ +@USE_AVAHI_TRUE@@USE_CURL_FALSE@@USE_LIBSOUP_FALSE@ src/libostree/ostree-soup-uri.c \ +@USE_AVAHI_TRUE@@USE_CURL_FALSE@@USE_LIBSOUP_FALSE@ src/libostree/ostree-soup-form.c \ +@USE_AVAHI_TRUE@@USE_CURL_FALSE@@USE_LIBSOUP_FALSE@ $(NULL) + +@USE_LIBMOUNT_TRUE@am__append_42 = $(OT_DEP_LIBMOUNT_CFLAGS) +@USE_LIBMOUNT_TRUE@am__append_43 = $(OT_DEP_LIBMOUNT_LIBS) +@USE_SELINUX_TRUE@am__append_44 = $(OT_DEP_SELINUX_CFLAGS) +@USE_SELINUX_TRUE@am__append_45 = $(OT_DEP_SELINUX_LIBS) +@USE_LIBSODIUM_TRUE@am__append_46 = $(OT_DEP_LIBSODIUM_CFLAGS) +@USE_LIBSODIUM_TRUE@am__append_47 = $(OT_DEP_LIBSODIUM_LIBS) +# When compiling this is set via config.h, but g-ir-scanner can't use that +@BUILDOPT_INTROSPECTION_TRUE@@ENABLE_EXPERIMENTAL_API_TRUE@am__append_48 = -DOSTREE_ENABLE_EXPERIMENTAL_API=1 +@BUILDOPT_INTROSPECTION_TRUE@am__append_49 = OSTree-1.0.gir +@BUILDOPT_INTROSPECTION_TRUE@am__append_50 = OSTree-1.0.gir +@BUILDOPT_INTROSPECTION_TRUE@am__append_51 = OSTree-1.0.typelib +@BUILDOPT_INTROSPECTION_TRUE@am__append_52 = $(gir_DATA) $(typelib_DATA) +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_53 = \ +@ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL) + +@USE_GPGME_TRUE@am__append_54 = \ +@USE_GPGME_TRUE@ src/ostree/ot-builtin-gpg-sign.c \ +@USE_GPGME_TRUE@ $(NULL) + +@USE_GPGME_TRUE@am__append_55 = \ +@USE_GPGME_TRUE@ src/ostree/ot-remote-builtin-gpg-import.c \ +@USE_GPGME_TRUE@ $(NULL) + +@USE_CURL_OR_SOUP_TRUE@am__append_56 = src/ostree/ot-remote-builtin-add-cookie.c \ +@USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-builtin-delete-cookie.c \ +@USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-builtin-list-cookies.c \ +@USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-cookie-util.h \ +@USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-cookie-util.c \ +@USE_CURL_OR_SOUP_TRUE@ $(NULL) src/ostree/ot-builtin-pull.c + +# Eventually once we stop things from using this, we should support disabling this +@USE_LIBSOUP_TRUE@am__append_57 = src/ostree/ot-builtin-trivial-httpd.c +@USE_LIBSOUP_TRUE@am__append_58 = ostree-trivial-httpd + +# This is necessary for the cookie jar bits +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_59 = $(OT_INTERNAL_SOUP_CFLAGS) +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_60 = $(OT_INTERNAL_SOUP_LIBS) +@USE_LIBARCHIVE_TRUE@am__append_61 = $(OT_DEP_LIBARCHIVE_CFLAGS) +@USE_LIBARCHIVE_TRUE@am__append_62 = $(OT_DEP_LIBARCHIVE_LIBS) +@USE_LIBSODIUM_TRUE@am__append_63 = $(OT_DEP_LIBSODIUM_CFLAGS) +@USE_LIBSODIUM_TRUE@am__append_64 = $(OT_DEP_LIBSODIUM_LIBS) +@BUILDOPT_SYSTEMD_TRUE@am__append_65 = ostree-remount +# It is built anyway as a side-effect of having the symlink in tests/, +# and if we declare it here, it gets cleaned up properly +@BUILDOPT_SYSTEMD_FALSE@am__append_66 = ostree-remount + +# ostree-prepare-root can be used as init in a system without a populated /lib. +# To support this use case we need to link statically as we will be unable to +# locate libc.so at run time if it's not installed in /lib. +# +# We support building ostree-prepare-root with a different compiler to the rest +# of ostree so we can use musl rather than glibc. This reduces the size of the +# executable significantly: from ~700K -> ~30K. We have to use _SCRIPTS here +# to get autotools to install this as an executable but without generating rules +# to make it itself which we have specified manually. See +# https://lists.gnu.org/archive/html/help-gnu-utils/2007-01/msg00007.html +@BUILDOPT_USE_STATIC_COMPILER_TRUE@am__append_67 = ostree-prepare-root +@BUILDOPT_USE_STATIC_COMPILER_FALSE@am__append_68 = ostree-prepare-root +@BUILDOPT_SYSTEMD_TRUE@am__append_69 = -DHAVE_SYSTEMD=1 + +# This is the "new mode" of using a generator for /var; see +# https://github.com/ostreedev/ostree/issues/855 +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_70 = -DHAVE_SYSTEMD_AND_LIBMOUNT=1 +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_71 = -DHAVE_SYSTEMD_AND_LIBMOUNT=1 +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@systemdsystemgenerator_PROGRAMS = ostree-system-generator$(EXEEXT) +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_72 = $(systemdsystemgenerator_PROGRAMS) + +# Allow the distcheck install under $prefix test to pass +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_73 = --with-systemdsystemgeneratordir='$${libdir}/systemd/system-generators' +@BUILDOPT_FUSE_TRUE@am__append_74 = rofiles-fuse +@BUILDOPT_ASAN_TRUE@am__append_75 = OT_SKIP_READDIR_RAND=1 G_SLICE=always-malloc +@USE_GPGME_TRUE@am__append_76 = \ +@USE_GPGME_TRUE@ tests/test-remote-gpg-import.sh \ +@USE_GPGME_TRUE@ tests/test-gpg-signed-commit.sh \ +@USE_GPGME_TRUE@ tests/test-admin-gpg.sh \ +@USE_GPGME_TRUE@ $(NULL) + +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_77 = $(experimental_test_scripts) +@ENABLE_EXPERIMENTAL_API_FALSE@am__append_78 = $(experimental_test_scripts) +@BUILDOPT_FUSE_TRUE@am__append_79 = tests/test-rofiles-fuse.sh +@BUILDOPT_FUSE_TRUE@am__append_80 = tests/rofiles-fuse-symlink-stamp +@BUILDOPT_FUSE_FALSE@am__append_81 = tests/test-rofiles-fuse.sh +@USE_LIBSOUP_TRUE@am__append_82 = tests/test-remote-cookies.sh +@BUILDOPT_GJS_TRUE@am__append_83 = $(js_tests) $(js_installed_tests) +@BUILDOPT_GJS_FALSE@am__append_84 = $(js_tests) +@BUILDOPT_GJS_FALSE@am__append_85 = $(js_installed_tests) +@ENABLE_INSTALLED_TESTS_FALSE@am__append_86 = -rpath $(abs_builddir) +@USE_GPGME_TRUE@am__append_87 = \ +@USE_GPGME_TRUE@ tests/test-gpg-verify-result \ +@USE_GPGME_TRUE@ $(NULL) + +@USE_AVAHI_TRUE@am__append_88 = tests/test-repo-finder-avahi +@USE_LIBARCHIVE_TRUE@am__append_89 = tests/test-libarchive-import +@USE_GPGME_TRUE@am__append_90 = \ +@USE_GPGME_TRUE@ tests/gpg-verify-data/README.md \ +@USE_GPGME_TRUE@ $(NULL) + +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_91 = $(_installed_or_uninstalled_test_scripts) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_92 = $(_installed_or_uninstalled_test_programs) +@ENABLE_INSTALLED_TESTS_TRUE@am__append_93 = install-installed-tests-extra + +# Allow the distcheck install under $prefix test to pass +@BUILDOPT_SYSTEMD_TRUE@am__append_94 = --with-systemdsystemunitdir='$${libdir}/systemd/system' + +# We're using the system grub2-mkconfig generator +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_95 = src/boot/grub2/grub2-15_ostree +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_96 = install-grub2-config-hook +# We're using our internal generator +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE@am__append_97 = src/boot/grub2/ostree-grub-generator +@ENABLE_MAN_TRUE@@USE_LIBSOUP_TRUE@am__append_98 = ostree-trivial-httpd.1 +# We still want to distribute the source, even if we are not building it +@ENABLE_MAN_TRUE@@USE_LIBSOUP_FALSE@am__append_99 = man/ostree-trivial-httpd.xml +@BUILDOPT_FUSE_TRUE@@ENABLE_MAN_TRUE@am__append_100 = rofiles-fuse.1 +@ENABLE_MAN_TRUE@@USE_GPGME_TRUE@am__append_101 = ostree-gpg-sign.1 +@ENABLE_MAN_TRUE@am__append_102 = $(man1_MANS:.1=.xml) $(man5_MANS:.5=.xml) +@ENABLE_MAN_TRUE@am__append_103 = \ +@ENABLE_MAN_TRUE@ $(man1_MANS) \ +@ENABLE_MAN_TRUE@ $(man5_MANS) \ +@ENABLE_MAN_TRUE@ $(NULL) + +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/buildutil/attributes.m4 \ + $(top_srcdir)/buildutil/glibtests.m4 \ + $(top_srcdir)/buildutil/gtk-doc.m4 \ + $(top_srcdir)/buildutil/libglnx.m4 \ + $(top_srcdir)/buildutil/libtool.m4 \ + $(top_srcdir)/buildutil/ltoptions.m4 \ + $(top_srcdir)/buildutil/ltsugar.m4 \ + $(top_srcdir)/buildutil/ltversion.m4 \ + $(top_srcdir)/buildutil/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(dist_completions_DATA) \ + $(am__dist_gpginsttest_DATA_DIST) \ + $(am__dist_gpginsttest_revoc_DATA_DIST) \ + $(am__dist_gpginsttest_trusted_DATA_DIST) \ + $(am__dist_gpgvinsttest_DATA_DIST) \ + $(am__dist_systemdtmpfiles_DATA_DIST) \ + $(libostreeinclude_HEADERS) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = src/libostree/ostree-1.pc \ + src/libostree/ostree-version.h +CONFIG_CLEAN_VPATH_FILES = +@BUILDOPT_FUSE_TRUE@am__EXEEXT_1 = rofiles-fuse$(EXEEXT) +am__installdirs = "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libexecdir)" \ + "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" \ + "$(DESTDIR)$(sbindir)" \ + "$(DESTDIR)$(systemdsystemgeneratordir)" \ + "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libdir)" \ + "$(DESTDIR)$(privlibdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(dracutmoddir)" "$(DESTDIR)$(installed_testdir)" \ + "$(DESTDIR)$(mkinitcpioinstalldir)" \ + "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" \ + "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" \ + "$(DESTDIR)$(completionsdir)" "$(DESTDIR)$(gpginsttestdir)" \ + "$(DESTDIR)$(gpginsttest_revocdir)" \ + "$(DESTDIR)$(gpginsttest_trusteddir)" \ + "$(DESTDIR)$(gpgvinsttestdir)" \ + "$(DESTDIR)$(systemdtmpfilesdir)" "$(DESTDIR)$(dracutconfdir)" \ + "$(DESTDIR)$(girdir)" "$(DESTDIR)$(gpgreadmedir)" \ + "$(DESTDIR)$(installed_testdir)" \ + "$(DESTDIR)$(installed_test_metadir)" \ + "$(DESTDIR)$(mkinitcpioconfdir)" \ + "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(pkgconfigdir)" \ + "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(typelibdir)" \ + "$(DESTDIR)$(libostreeincludedir)" +am__EXEEXT_2 = +@USE_AVAHI_TRUE@am__EXEEXT_3 = tests/test-repo-finder-avahi$(EXEEXT) +@USE_GPGME_TRUE@am__EXEEXT_4 = tests/test-gpg-verify-result$(EXEEXT) \ +@USE_GPGME_TRUE@ $(am__EXEEXT_2) +@USE_LIBARCHIVE_TRUE@am__EXEEXT_5 = \ +@USE_LIBARCHIVE_TRUE@ tests/test-libarchive-import$(EXEEXT) +am__EXEEXT_6 = tests/test-varint$(EXEEXT) \ + tests/test-ot-unix-utils$(EXEEXT) tests/test-bsdiff$(EXEEXT) \ + tests/test-mutable-tree$(EXEEXT) \ + tests/test-keyfile-utils$(EXEEXT) \ + tests/test-ot-opt-utils$(EXEEXT) \ + tests/test-ot-tool-util$(EXEEXT) tests/test-checksum$(EXEEXT) \ + tests/test-lzma$(EXEEXT) tests/test-rollsum$(EXEEXT) \ + tests/test-basic-c$(EXEEXT) tests/test-sysroot-c$(EXEEXT) \ + tests/test-pull-c$(EXEEXT) tests/test-repo$(EXEEXT) \ + tests/test-include-ostree-h$(EXEEXT) tests/test-kargs$(EXEEXT) \ + $(am__EXEEXT_4) $(am__EXEEXT_5) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__EXEEXT_7 = \ +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@ $(am__EXEEXT_6) +am__EXEEXT_8 = tests/test-bloom$(EXEEXT) \ + tests/test-repo-finder-config$(EXEEXT) \ + tests/test-repo-finder-mount$(EXEEXT) $(am__EXEEXT_2) \ + $(am__EXEEXT_3) $(am__EXEEXT_7) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@am__EXEEXT_9 = $(am__EXEEXT_6) +am__EXEEXT_10 = tests/get-byte-order$(EXEEXT) \ + tests/repo-finder-mount$(EXEEXT) $(am__EXEEXT_2) +am__EXEEXT_11 = $(am__EXEEXT_8) $(am__EXEEXT_9) $(am__EXEEXT_10) +@ENABLE_ALWAYS_BUILD_TESTS_FALSE@am__EXEEXT_12 = $(am__EXEEXT_11) +am__EXEEXT_13 = test-libglnx-xattrs$(EXEEXT) \ + test-libglnx-fdio$(EXEEXT) test-libglnx-errors$(EXEEXT) \ + test-libglnx-macros$(EXEEXT) test-libglnx-shutil$(EXEEXT) +@BUILDOPT_SYSTEMD_FALSE@am__EXEEXT_14 = ostree-remount$(EXEEXT) +@ENABLE_INSTALLED_TESTS_TRUE@am__EXEEXT_15 = $(am__EXEEXT_8) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(am__EXEEXT_9) $(am__EXEEXT_10) +@ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__EXEEXT_16 = $(am__EXEEXT_11) +@BUILDOPT_SYSTEMD_TRUE@am__EXEEXT_17 = ostree-remount$(EXEEXT) +@BUILDOPT_USE_STATIC_COMPILER_FALSE@am__EXEEXT_18 = ostree-prepare-root$(EXEEXT) +@USE_LIBSOUP_TRUE@am__EXEEXT_19 = ostree-trivial-httpd$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(installed_test_PROGRAMS) \ + $(libexec_PROGRAMS) $(noinst_PROGRAMS) $(ostree_boot_PROGRAMS) \ + $(pkglibexec_PROGRAMS) $(sbin_PROGRAMS) \ + $(systemdsystemgenerator_PROGRAMS) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +LTLIBRARIES = $(installed_test_LTLIBRARIES) $(lib_LTLIBRARIES) \ + $(noinst_LTLIBRARIES) $(privlib_LTLIBRARIES) +libbsdiff_la_LIBADD = +am__dirstamp = $(am__leading_dot)dirstamp +am__objects_1 = +am_libbsdiff_la_OBJECTS = bsdiff/libbsdiff_la-bsdiff.lo \ + bsdiff/libbsdiff_la-bspatch.lo $(am__objects_1) +libbsdiff_la_OBJECTS = $(am_libbsdiff_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libbsdiff_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libbsdiff_la_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +libbupsplit_la_LIBADD = +am__libbupsplit_la_SOURCES_DIST = src/libostree/bupsplit.h \ + src/libostree/bupsplit.c +@ENABLE_RUST_FALSE@am_libbupsplit_la_OBJECTS = \ +@ENABLE_RUST_FALSE@ src/libostree/bupsplit.lo +libbupsplit_la_OBJECTS = $(am_libbupsplit_la_OBJECTS) +@ENABLE_RUST_FALSE@am_libbupsplit_la_rpath = +am__DEPENDENCIES_1 = +am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) +libglnx_la_DEPENDENCIES = $(am__DEPENDENCIES_2) +am_libglnx_la_OBJECTS = libglnx/la-glnx-backports.lo \ + libglnx/la-glnx-local-alloc.lo libglnx/la-glnx-errors.lo \ + libglnx/la-glnx-console.lo libglnx/la-glnx-dirfd.lo \ + libglnx/la-glnx-fdio.lo libglnx/la-glnx-lockfile.lo \ + libglnx/la-glnx-xattrs.lo libglnx/la-glnx-shutil.lo \ + $(am__objects_1) +libglnx_la_OBJECTS = $(am_libglnx_la_OBJECTS) +libglnx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libglnx_la_CFLAGS) \ + $(CFLAGS) $(libglnx_la_LDFLAGS) $(LDFLAGS) -o $@ +@USE_GPGME_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) \ +@USE_GPGME_TRUE@ $(am__DEPENDENCIES_1) +@USE_LIBARCHIVE_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1) +@USE_AVAHI_TRUE@am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1) +@BUILDOPT_SYSTEMD_TRUE@am__DEPENDENCIES_6 = $(am__DEPENDENCIES_1) +@USE_CURL_TRUE@am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1) +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__DEPENDENCIES_8 = \ +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@ $(am__DEPENDENCIES_2) +@USE_LIBMOUNT_TRUE@am__DEPENDENCIES_9 = $(am__DEPENDENCIES_1) +@USE_SELINUX_TRUE@am__DEPENDENCIES_10 = $(am__DEPENDENCIES_1) +@USE_LIBSODIUM_TRUE@am__DEPENDENCIES_11 = $(am__DEPENDENCIES_1) +libostree_1_la_DEPENDENCIES = libotutil.la libglnx.la libbsdiff.la \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(bupsplitpath) \ + $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_5) \ + $(am__DEPENDENCIES_6) $(am__DEPENDENCIES_7) \ + $(am__DEPENDENCIES_8) $(am__DEPENDENCIES_9) \ + $(am__DEPENDENCIES_10) $(am__DEPENDENCIES_11) +am__libostree_1_la_SOURCES_DIST = \ + src/libostree/ostree-async-progress.c \ + src/libostree/ostree-cmdprivate.h \ + src/libostree/ostree-cmdprivate.c \ + src/libostree/ostree-core-private.h \ + src/libostree/ostree-core.c \ + src/libostree/ostree-dummy-enumtypes.c \ + src/libostree/ostree-checksum-input-stream.c \ + src/libostree/ostree-checksum-input-stream.h \ + src/libostree/ostree-chain-input-stream.c \ + src/libostree/ostree-chain-input-stream.h \ + src/libostree/ostree-lzma-common.c \ + src/libostree/ostree-lzma-common.h \ + src/libostree/ostree-lzma-compressor.c \ + src/libostree/ostree-lzma-compressor.h \ + src/libostree/ostree-lzma-decompressor.c \ + src/libostree/ostree-lzma-decompressor.h \ + src/libostree/ostree-rollsum.h src/libostree/ostree-rollsum.c \ + src/libostree/ostree-varint.h src/libostree/ostree-varint.c \ + src/libostree/ostree-linuxfsutil.h \ + src/libostree/ostree-linuxfsutil.c src/libostree/ostree-diff.c \ + src/libostree/ostree-mutable-tree.c src/libostree/ostree-ref.c \ + src/libostree/ostree-remote.c \ + src/libostree/ostree-remote-private.h \ + src/libostree/ostree-repo.c \ + src/libostree/ostree-repo-checkout.c \ + src/libostree/ostree-repo-commit.c \ + src/libostree/ostree-repo-pull.c \ + src/libostree/ostree-repo-pull-private.h \ + src/libostree/ostree-repo-pull-verify.c \ + src/libostree/ostree-repo-libarchive.c \ + src/libostree/ostree-repo-prune.c \ + src/libostree/ostree-repo-refs.c \ + src/libostree/ostree-repo-traverse.c \ + src/libostree/ostree-repo-private.h \ + src/libostree/ostree-repo-file.c \ + src/libostree/ostree-repo-file-enumerator.c \ + src/libostree/ostree-repo-file-enumerator.h \ + src/libostree/ostree-sepolicy.c \ + src/libostree/ostree-sepolicy-private.h \ + src/libostree/ostree-sysroot-private.h \ + src/libostree/ostree-sysroot.c \ + src/libostree/ostree-sysroot-cleanup.c \ + src/libostree/ostree-sysroot-deploy.c \ + src/libostree/ostree-sysroot-upgrader.c \ + src/libostree/ostree-impl-system-generator.c \ + src/libostree/ostree-bootconfig-parser.c \ + src/libostree/ostree-deployment.c \ + src/libostree/ostree-bootloader.h \ + src/libostree/ostree-bootloader.c \ + src/libostree/ostree-bootloader-grub2.h \ + src/libostree/ostree-bootloader-grub2.c \ + src/libostree/ostree-bootloader-zipl.h \ + src/libostree/ostree-bootloader-zipl.c \ + src/libostree/ostree-bootloader-syslinux.h \ + src/libostree/ostree-bootloader-syslinux.c \ + src/libostree/ostree-bootloader-uboot.h \ + src/libostree/ostree-bootloader-uboot.c \ + src/libostree/ostree-repo-static-delta-core.c \ + src/libostree/ostree-repo-static-delta-processing.c \ + src/libostree/ostree-repo-static-delta-compilation.c \ + src/libostree/ostree-repo-static-delta-compilation-analysis.c \ + src/libostree/ostree-repo-static-delta-private.h \ + src/libostree/ostree-autocleanups.h \ + src/libostree/ostree-bloom.c \ + src/libostree/ostree-bloom-private.h \ + src/libostree/ostree-repo-finder.c \ + src/libostree/ostree-repo-finder-avahi.c \ + src/libostree/ostree-repo-finder-config.c \ + src/libostree/ostree-repo-finder-mount.c \ + src/libostree/ostree-repo-finder-override.c \ + src/libostree/ostree-kernel-args.h \ + src/libostree/ostree-kernel-args.c \ + src/libostree/ostree-libarchive-input-stream.h \ + src/libostree/ostree-libarchive-input-stream.c \ + src/libostree/ostree-libarchive-private.h \ + src/libostree/ostree-tls-cert-interaction.c \ + src/libostree/ostree-tls-cert-interaction.h \ + src/libostree/ostree-repo-finder-avahi-parser.c \ + src/libostree/ostree-repo-finder-avahi-private.h \ + src/libostree/ostree-gpg-verifier.c \ + src/libostree/ostree-gpg-verifier.h \ + src/libostree/ostree-gpg-verify-result.c \ + src/libostree/ostree-gpg-verify-result-private.h \ + src/libostree/ostree-gpg-verify-result-dummy.c \ + src/libostree/ostree-fetcher.h \ + src/libostree/ostree-fetcher-util.h \ + src/libostree/ostree-fetcher-util.c \ + src/libostree/ostree-fetcher-uri.c \ + src/libostree/ostree-metalink.h \ + src/libostree/ostree-metalink.c \ + src/libostree/ostree-fetcher-curl.c \ + src/libostree/ostree-soup-uri.h \ + src/libostree/ostree-soup-uri.c \ + src/libostree/ostree-soup-form.c \ + src/libostree/ostree-fetcher-soup.c \ + src/libostree/ostree-sign.c src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-dummy.c \ + src/libostree/ostree-sign-dummy.h \ + src/libostree/ostree-sign-ed25519.c \ + src/libostree/ostree-sign-ed25519.h +@USE_LIBARCHIVE_TRUE@am__objects_2 = src/libostree/libostree_1_la-ostree-libarchive-input-stream.lo \ +@USE_LIBARCHIVE_TRUE@ $(am__objects_1) +@HAVE_LIBSOUP_CLIENT_CERTS_TRUE@am__objects_3 = src/libostree/libostree_1_la-ostree-tls-cert-interaction.lo \ +@HAVE_LIBSOUP_CLIENT_CERTS_TRUE@ $(am__objects_1) +am__objects_4 = $(am__objects_1) +@ENABLE_EXPERIMENTAL_API_FALSE@am__objects_5 = $(am__objects_4) +@ENABLE_EXPERIMENTAL_API_TRUE@am__objects_6 = $(am__objects_1) +@USE_AVAHI_TRUE@am__objects_7 = src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo \ +@USE_AVAHI_TRUE@ $(am__objects_1) +@USE_GPGME_TRUE@am__objects_8 = src/libostree/libostree_1_la-ostree-gpg-verifier.lo \ +@USE_GPGME_TRUE@ src/libostree/libostree_1_la-ostree-gpg-verify-result.lo \ +@USE_GPGME_TRUE@ $(am__objects_1) +@USE_GPGME_FALSE@am__objects_9 = src/libostree/libostree_1_la-ostree-gpg-verify-result-dummy.lo \ +@USE_GPGME_FALSE@ $(am__objects_1) +@USE_CURL_OR_SOUP_TRUE@am__objects_10 = src/libostree/libostree_1_la-ostree-fetcher-util.lo \ +@USE_CURL_OR_SOUP_TRUE@ src/libostree/libostree_1_la-ostree-fetcher-uri.lo \ +@USE_CURL_OR_SOUP_TRUE@ src/libostree/libostree_1_la-ostree-metalink.lo \ +@USE_CURL_OR_SOUP_TRUE@ $(am__objects_1) +@USE_CURL_TRUE@am__objects_11 = src/libostree/libostree_1_la-ostree-fetcher-curl.lo \ +@USE_CURL_TRUE@ src/libostree/libostree_1_la-ostree-soup-uri.lo \ +@USE_CURL_TRUE@ src/libostree/libostree_1_la-ostree-soup-form.lo \ +@USE_CURL_TRUE@ $(am__objects_1) +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__objects_12 = src/libostree/libostree_1_la-ostree-fetcher-soup.lo +@USE_AVAHI_TRUE@@USE_CURL_FALSE@@USE_LIBSOUP_FALSE@am__objects_13 = src/libostree/libostree_1_la-ostree-soup-uri.lo \ +@USE_AVAHI_TRUE@@USE_CURL_FALSE@@USE_LIBSOUP_FALSE@ src/libostree/libostree_1_la-ostree-soup-form.lo \ +@USE_AVAHI_TRUE@@USE_CURL_FALSE@@USE_LIBSOUP_FALSE@ $(am__objects_1) +am_libostree_1_la_OBJECTS = \ + src/libostree/libostree_1_la-ostree-async-progress.lo \ + src/libostree/libostree_1_la-ostree-cmdprivate.lo \ + src/libostree/libostree_1_la-ostree-core.lo \ + src/libostree/libostree_1_la-ostree-dummy-enumtypes.lo \ + src/libostree/libostree_1_la-ostree-checksum-input-stream.lo \ + src/libostree/libostree_1_la-ostree-chain-input-stream.lo \ + src/libostree/libostree_1_la-ostree-lzma-common.lo \ + src/libostree/libostree_1_la-ostree-lzma-compressor.lo \ + src/libostree/libostree_1_la-ostree-lzma-decompressor.lo \ + src/libostree/libostree_1_la-ostree-rollsum.lo \ + src/libostree/libostree_1_la-ostree-varint.lo \ + src/libostree/libostree_1_la-ostree-linuxfsutil.lo \ + src/libostree/libostree_1_la-ostree-diff.lo \ + src/libostree/libostree_1_la-ostree-mutable-tree.lo \ + src/libostree/libostree_1_la-ostree-ref.lo \ + src/libostree/libostree_1_la-ostree-remote.lo \ + src/libostree/libostree_1_la-ostree-repo.lo \ + src/libostree/libostree_1_la-ostree-repo-checkout.lo \ + src/libostree/libostree_1_la-ostree-repo-commit.lo \ + src/libostree/libostree_1_la-ostree-repo-pull.lo \ + src/libostree/libostree_1_la-ostree-repo-pull-verify.lo \ + src/libostree/libostree_1_la-ostree-repo-libarchive.lo \ + src/libostree/libostree_1_la-ostree-repo-prune.lo \ + src/libostree/libostree_1_la-ostree-repo-refs.lo \ + src/libostree/libostree_1_la-ostree-repo-traverse.lo \ + src/libostree/libostree_1_la-ostree-repo-file.lo \ + src/libostree/libostree_1_la-ostree-repo-file-enumerator.lo \ + src/libostree/libostree_1_la-ostree-sepolicy.lo \ + src/libostree/libostree_1_la-ostree-sysroot.lo \ + src/libostree/libostree_1_la-ostree-sysroot-cleanup.lo \ + src/libostree/libostree_1_la-ostree-sysroot-deploy.lo \ + src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo \ + src/libostree/libostree_1_la-ostree-impl-system-generator.lo \ + src/libostree/libostree_1_la-ostree-bootconfig-parser.lo \ + src/libostree/libostree_1_la-ostree-deployment.lo \ + src/libostree/libostree_1_la-ostree-bootloader.lo \ + src/libostree/libostree_1_la-ostree-bootloader-grub2.lo \ + src/libostree/libostree_1_la-ostree-bootloader-zipl.lo \ + src/libostree/libostree_1_la-ostree-bootloader-syslinux.lo \ + src/libostree/libostree_1_la-ostree-bootloader-uboot.lo \ + src/libostree/libostree_1_la-ostree-repo-static-delta-core.lo \ + src/libostree/libostree_1_la-ostree-repo-static-delta-processing.lo \ + src/libostree/libostree_1_la-ostree-repo-static-delta-compilation.lo \ + src/libostree/libostree_1_la-ostree-repo-static-delta-compilation-analysis.lo \ + src/libostree/libostree_1_la-ostree-bloom.lo \ + src/libostree/libostree_1_la-ostree-repo-finder.lo \ + src/libostree/libostree_1_la-ostree-repo-finder-avahi.lo \ + src/libostree/libostree_1_la-ostree-repo-finder-config.lo \ + src/libostree/libostree_1_la-ostree-repo-finder-mount.lo \ + src/libostree/libostree_1_la-ostree-repo-finder-override.lo \ + src/libostree/libostree_1_la-ostree-kernel-args.lo \ + $(am__objects_1) $(am__objects_2) $(am__objects_3) \ + $(am__objects_5) $(am__objects_6) $(am__objects_7) \ + $(am__objects_8) $(am__objects_9) $(am__objects_10) \ + $(am__objects_11) $(am__objects_12) $(am__objects_13) \ + src/libostree/libostree_1_la-ostree-sign.lo \ + src/libostree/libostree_1_la-ostree-sign-dummy.lo \ + src/libostree/libostree_1_la-ostree-sign-ed25519.lo \ + $(am__objects_1) +nodist_libostree_1_la_OBJECTS = \ + src/libostree/libostree_1_la-ostree-enumtypes.lo \ + $(am__objects_1) +libostree_1_la_OBJECTS = $(am_libostree_1_la_OBJECTS) \ + $(nodist_libostree_1_la_OBJECTS) +libostree_1_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libostree_1_la_CFLAGS) $(CFLAGS) $(libostree_1_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__DEPENDENCIES_12 = libglnx.la libotutil.la libostree-1.la \ + $(am__DEPENDENCIES_2) +am__DEPENDENCIES_13 = $(am__DEPENDENCIES_12) $(am__DEPENDENCIES_2) +libostreetest_la_DEPENDENCIES = $(am__DEPENDENCIES_13) +am_libostreetest_la_OBJECTS = tests/libostreetest_la-libostreetest.lo \ + tests/libostreetest_la-test-mock-gio.lo +libostreetest_la_OBJECTS = $(am_libostreetest_la_OBJECTS) +libostreetest_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libostreetest_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +libotutil_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1) +am__libotutil_la_SOURCES_DIST = src/libotutil/ot-checksum-utils.c \ + src/libotutil/ot-checksum-utils.h \ + src/libotutil/ot-checksum-instream.c \ + src/libotutil/ot-checksum-instream.h \ + src/libotutil/ot-fs-utils.c src/libotutil/ot-fs-utils.h \ + src/libotutil/ot-keyfile-utils.c \ + src/libotutil/ot-keyfile-utils.h src/libotutil/ot-opt-utils.c \ + src/libotutil/ot-opt-utils.h src/libotutil/ot-unix-utils.c \ + src/libotutil/ot-unix-utils.h src/libotutil/ot-variant-utils.c \ + src/libotutil/ot-variant-utils.h \ + src/libotutil/ot-variant-builder.c \ + src/libotutil/ot-variant-builder.h \ + src/libotutil/ot-gio-utils.c src/libotutil/ot-gio-utils.h \ + src/libotutil/otutil.h src/libotutil/ot-tool-util.c \ + src/libotutil/ot-tool-util.h src/libotutil/ot-gpg-utils.c \ + src/libotutil/ot-gpg-utils.h +@USE_GPGME_TRUE@am__objects_14 = \ +@USE_GPGME_TRUE@ src/libotutil/libotutil_la-ot-gpg-utils.lo \ +@USE_GPGME_TRUE@ $(am__objects_1) +am_libotutil_la_OBJECTS = \ + src/libotutil/libotutil_la-ot-checksum-utils.lo \ + src/libotutil/libotutil_la-ot-checksum-instream.lo \ + src/libotutil/libotutil_la-ot-fs-utils.lo \ + src/libotutil/libotutil_la-ot-keyfile-utils.lo \ + src/libotutil/libotutil_la-ot-opt-utils.lo \ + src/libotutil/libotutil_la-ot-unix-utils.lo \ + src/libotutil/libotutil_la-ot-variant-utils.lo \ + src/libotutil/libotutil_la-ot-variant-builder.lo \ + src/libotutil/libotutil_la-ot-gio-utils.lo \ + src/libotutil/libotutil_la-ot-tool-util.lo $(am__objects_1) \ + $(am__objects_14) +libotutil_la_OBJECTS = $(am_libotutil_la_OBJECTS) +libotutil_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libotutil_la_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +libreaddir_rand_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_1) +am_libreaddir_rand_la_OBJECTS = \ + tests/libreaddir_rand_la-readdir-rand.lo +libreaddir_rand_la_OBJECTS = $(am_libreaddir_rand_la_OBJECTS) +libreaddir_rand_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libreaddir_rand_la_CFLAGS) $(CFLAGS) \ + $(libreaddir_rand_la_LDFLAGS) $(LDFLAGS) -o $@ +@ENABLE_ALWAYS_BUILD_TESTS_FALSE@am_libreaddir_rand_la_rpath = +@ENABLE_ALWAYS_BUILD_TESTS_TRUE@am_libreaddir_rand_la_rpath = +@ENABLE_INSTALLED_TESTS_TRUE@am_libreaddir_rand_la_rpath = -rpath \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(installed_testdir) +am__ostree_SOURCES_DIST = src/ostree/main.c \ + src/ostree/ot-builtin-admin.c src/ostree/ot-builtins.h \ + src/ostree/ot-builtin-cat.c src/ostree/ot-builtin-config.c \ + src/ostree/ot-builtin-checkout.c \ + src/ostree/ot-builtin-checksum.c \ + src/ostree/ot-builtin-commit.c \ + src/ostree/ot-builtin-create-usb.c \ + src/ostree/ot-builtin-diff.c src/ostree/ot-builtin-export.c \ + src/ostree/ot-builtin-find-remotes.c \ + src/ostree/ot-builtin-fsck.c src/ostree/ot-builtin-init.c \ + src/ostree/ot-builtin-pull-local.c src/ostree/ot-builtin-log.c \ + src/ostree/ot-builtin-ls.c src/ostree/ot-builtin-prune.c \ + src/ostree/ot-builtin-refs.c src/ostree/ot-builtin-remote.c \ + src/ostree/ot-builtin-reset.c \ + src/ostree/ot-builtin-rev-parse.c src/ostree/ot-builtin-sign.c \ + src/ostree/ot-builtin-summary.c src/ostree/ot-builtin-show.c \ + src/ostree/ot-builtin-static-delta.c src/ostree/ot-main.h \ + src/ostree/ot-main.c src/ostree/ot-dump.h src/ostree/ot-dump.c \ + src/ostree/ot-editor.c src/ostree/ot-editor.h \ + src/ostree/parse-datetime.h src/ostree/ot-builtin-gpg-sign.c \ + src/ostree/ot-admin-builtin-init-fs.c \ + src/ostree/ot-admin-builtin-diff.c \ + src/ostree/ot-admin-builtin-deploy.c \ + src/ostree/ot-admin-builtin-finalize-staged.c \ + src/ostree/ot-admin-builtin-undeploy.c \ + src/ostree/ot-admin-builtin-instutil.c \ + src/ostree/ot-admin-builtin-cleanup.c \ + src/ostree/ot-admin-builtin-os-init.c \ + src/ostree/ot-admin-builtin-set-origin.c \ + src/ostree/ot-admin-builtin-status.c \ + src/ostree/ot-admin-builtin-switch.c \ + src/ostree/ot-admin-builtin-pin.c \ + src/ostree/ot-admin-builtin-upgrade.c \ + src/ostree/ot-admin-builtin-unlock.c \ + src/ostree/ot-admin-builtins.h \ + src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c \ + src/ostree/ot-admin-instutil-builtin-set-kargs.c \ + src/ostree/ot-admin-instutil-builtin-grub2-generate.c \ + src/ostree/ot-admin-instutil-builtins.h \ + src/ostree/ot-admin-functions.h \ + src/ostree/ot-admin-functions.c \ + src/ostree/ot-remote-builtins.h \ + src/ostree/ot-remote-builtin-add.c \ + src/ostree/ot-remote-builtin-delete.c \ + src/ostree/ot-remote-builtin-list.c \ + src/ostree/ot-remote-builtin-show-url.c \ + src/ostree/ot-remote-builtin-refs.c \ + src/ostree/ot-remote-builtin-summary.c \ + src/ostree/ot-remote-builtin-gpg-import.c \ + src/ostree/ot-remote-builtin-add-cookie.c \ + src/ostree/ot-remote-builtin-delete-cookie.c \ + src/ostree/ot-remote-builtin-list-cookies.c \ + src/ostree/ot-remote-cookie-util.h \ + src/ostree/ot-remote-cookie-util.c \ + src/ostree/ot-builtin-pull.c \ + src/ostree/ot-builtin-trivial-httpd.c +@USE_GPGME_TRUE@am__objects_15 = src/ostree/ostree-ot-builtin-gpg-sign.$(OBJEXT) \ +@USE_GPGME_TRUE@ $(am__objects_1) +@USE_GPGME_TRUE@am__objects_16 = src/ostree/ostree-ot-remote-builtin-gpg-import.$(OBJEXT) \ +@USE_GPGME_TRUE@ $(am__objects_1) +@USE_CURL_OR_SOUP_TRUE@am__objects_17 = src/ostree/ostree-ot-remote-builtin-add-cookie.$(OBJEXT) \ +@USE_CURL_OR_SOUP_TRUE@ src/ostree/ostree-ot-remote-builtin-delete-cookie.$(OBJEXT) \ +@USE_CURL_OR_SOUP_TRUE@ src/ostree/ostree-ot-remote-builtin-list-cookies.$(OBJEXT) \ +@USE_CURL_OR_SOUP_TRUE@ src/ostree/ostree-ot-remote-cookie-util.$(OBJEXT) \ +@USE_CURL_OR_SOUP_TRUE@ $(am__objects_1) \ +@USE_CURL_OR_SOUP_TRUE@ src/ostree/ostree-ot-builtin-pull.$(OBJEXT) +@USE_LIBSOUP_TRUE@am__objects_18 = src/ostree/ostree-ot-builtin-trivial-httpd.$(OBJEXT) +am_ostree_OBJECTS = src/ostree/ostree-main.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-admin.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-cat.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-config.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-checkout.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-checksum.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-commit.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-create-usb.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-diff.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-export.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-find-remotes.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-fsck.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-init.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-pull-local.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-log.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-ls.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-prune.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-refs.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-remote.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-reset.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-rev-parse.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-sign.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-summary.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-show.$(OBJEXT) \ + src/ostree/ostree-ot-builtin-static-delta.$(OBJEXT) \ + src/ostree/ostree-ot-main.$(OBJEXT) \ + src/ostree/ostree-ot-dump.$(OBJEXT) \ + src/ostree/ostree-ot-editor.$(OBJEXT) $(am__objects_1) \ + $(am__objects_6) $(am__objects_15) \ + src/ostree/ostree-ot-admin-builtin-init-fs.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-diff.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-deploy.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-finalize-staged.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-undeploy.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-instutil.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-cleanup.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-os-init.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-set-origin.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-status.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-switch.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-pin.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-upgrade.$(OBJEXT) \ + src/ostree/ostree-ot-admin-builtin-unlock.$(OBJEXT) \ + src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.$(OBJEXT) \ + src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.$(OBJEXT) \ + src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.$(OBJEXT) \ + src/ostree/ostree-ot-admin-functions.$(OBJEXT) \ + $(am__objects_1) \ + src/ostree/ostree-ot-remote-builtin-add.$(OBJEXT) \ + src/ostree/ostree-ot-remote-builtin-delete.$(OBJEXT) \ + src/ostree/ostree-ot-remote-builtin-list.$(OBJEXT) \ + src/ostree/ostree-ot-remote-builtin-show-url.$(OBJEXT) \ + src/ostree/ostree-ot-remote-builtin-refs.$(OBJEXT) \ + src/ostree/ostree-ot-remote-builtin-summary.$(OBJEXT) \ + $(am__objects_1) $(am__objects_16) $(am__objects_17) \ + $(am__objects_18) +nodist_ostree_OBJECTS = src/ostree/ostree-parse-datetime.$(OBJEXT) \ + $(am__objects_1) +ostree_OBJECTS = $(am_ostree_OBJECTS) $(nodist_ostree_OBJECTS) +ostree_DEPENDENCIES = $(am__DEPENDENCIES_12) libbsdiff.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_8) \ + $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_11) +ostree_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ostree_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +am_ostree_prepare_root_OBJECTS = src/switchroot/ostree_prepare_root-ostree-prepare-root.$(OBJEXT) \ + $(am__objects_1) +ostree_prepare_root_OBJECTS = $(am_ostree_prepare_root_OBJECTS) +@BUILDOPT_SYSTEMD_TRUE@ostree_prepare_root_DEPENDENCIES = \ +@BUILDOPT_SYSTEMD_TRUE@ $(am__DEPENDENCIES_1) +ostree_prepare_root_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(ostree_prepare_root_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_ostree_remount_OBJECTS = \ + src/switchroot/ostree_remount-ostree-remount.$(OBJEXT) \ + $(am__objects_1) +ostree_remount_OBJECTS = $(am_ostree_remount_OBJECTS) +ostree_remount_DEPENDENCIES = $(am__DEPENDENCIES_2) libglnx.la +am__ostree_system_generator_SOURCES_DIST = \ + src/switchroot/ostree-mount-util.h \ + src/switchroot/ostree-system-generator.c +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am_ostree_system_generator_OBJECTS = src/switchroot/ostree_system_generator-ostree-system-generator.$(OBJEXT) +ostree_system_generator_OBJECTS = \ + $(am_ostree_system_generator_OBJECTS) +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_DEPENDENCIES = \ +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ libglnx.la libostree-1.la \ +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ $(am__DEPENDENCIES_2) +ostree_system_generator_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(ostree_system_generator_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__ostree_trivial_httpd_SOURCES_DIST = \ + src/ostree/ostree-trivial-httpd.c +@USE_LIBSOUP_TRUE@am_ostree_trivial_httpd_OBJECTS = src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.$(OBJEXT) +ostree_trivial_httpd_OBJECTS = $(am_ostree_trivial_httpd_OBJECTS) +@USE_LIBSOUP_TRUE@ostree_trivial_httpd_DEPENDENCIES = \ +@USE_LIBSOUP_TRUE@ $(am__DEPENDENCIES_12) $(am__DEPENDENCIES_2) +ostree_trivial_httpd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(ostree_trivial_httpd_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__rofiles_fuse_SOURCES_DIST = src/rofiles-fuse/main.c +@BUILDOPT_FUSE_TRUE@am_rofiles_fuse_OBJECTS = src/rofiles-fuse/rofiles_fuse-main.$(OBJEXT) +rofiles_fuse_OBJECTS = $(am_rofiles_fuse_OBJECTS) +@BUILDOPT_FUSE_TRUE@rofiles_fuse_DEPENDENCIES = libglnx.la \ +@BUILDOPT_FUSE_TRUE@ $(am__DEPENDENCIES_1) \ +@BUILDOPT_FUSE_TRUE@ $(am__DEPENDENCIES_2) libostree-1.la +rofiles_fuse_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(rofiles_fuse_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +am__objects_19 = \ + libglnx/tests/test_libglnx_errors-libglnx-testlib.$(OBJEXT) +am_test_libglnx_errors_OBJECTS = $(am__objects_19) \ + libglnx/tests/test_libglnx_errors-test-libglnx-errors.$(OBJEXT) +test_libglnx_errors_OBJECTS = $(am_test_libglnx_errors_OBJECTS) +test_libglnx_errors_DEPENDENCIES = $(am__DEPENDENCIES_2) libglnx.la +test_libglnx_errors_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(test_libglnx_errors_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__objects_20 = \ + libglnx/tests/test_libglnx_fdio-libglnx-testlib.$(OBJEXT) +am_test_libglnx_fdio_OBJECTS = $(am__objects_20) \ + libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.$(OBJEXT) +test_libglnx_fdio_OBJECTS = $(am_test_libglnx_fdio_OBJECTS) +test_libglnx_fdio_DEPENDENCIES = $(am__DEPENDENCIES_2) libglnx.la +test_libglnx_fdio_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(test_libglnx_fdio_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +am__objects_21 = \ + libglnx/tests/test_libglnx_macros-libglnx-testlib.$(OBJEXT) +am_test_libglnx_macros_OBJECTS = $(am__objects_21) \ + libglnx/tests/test_libglnx_macros-test-libglnx-macros.$(OBJEXT) +test_libglnx_macros_OBJECTS = $(am_test_libglnx_macros_OBJECTS) +test_libglnx_macros_DEPENDENCIES = $(am__DEPENDENCIES_2) libglnx.la +test_libglnx_macros_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(test_libglnx_macros_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__objects_22 = \ + libglnx/tests/test_libglnx_shutil-libglnx-testlib.$(OBJEXT) +am_test_libglnx_shutil_OBJECTS = $(am__objects_22) \ + libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.$(OBJEXT) +test_libglnx_shutil_OBJECTS = $(am_test_libglnx_shutil_OBJECTS) +test_libglnx_shutil_DEPENDENCIES = $(am__DEPENDENCIES_2) libglnx.la +test_libglnx_shutil_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(test_libglnx_shutil_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__objects_23 = \ + libglnx/tests/test_libglnx_xattrs-libglnx-testlib.$(OBJEXT) +am_test_libglnx_xattrs_OBJECTS = $(am__objects_23) \ + libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.$(OBJEXT) +test_libglnx_xattrs_OBJECTS = $(am_test_libglnx_xattrs_OBJECTS) +test_libglnx_xattrs_DEPENDENCIES = $(am__DEPENDENCIES_2) libglnx.la +test_libglnx_xattrs_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_get_byte_order_OBJECTS = \ + tests/get_byte_order-get-byte-order.$(OBJEXT) +tests_get_byte_order_OBJECTS = $(am_tests_get_byte_order_OBJECTS) +tests_get_byte_order_DEPENDENCIES = $(am__DEPENDENCIES_1) +tests_get_byte_order_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_get_byte_order_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_repo_finder_mount_OBJECTS = \ + tests/repo_finder_mount-repo-finder-mount.$(OBJEXT) +tests_repo_finder_mount_OBJECTS = \ + $(am_tests_repo_finder_mount_OBJECTS) +tests_repo_finder_mount_DEPENDENCIES = $(am__DEPENDENCIES_13) \ + libostreetest.la +tests_repo_finder_mount_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_repo_finder_mount_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +tests_test_basic_c_SOURCES = tests/test-basic-c.c +tests_test_basic_c_OBJECTS = \ + tests/test_basic_c-test-basic-c.$(OBJEXT) +am__DEPENDENCIES_14 = $(am__DEPENDENCIES_13) libostreetest.la +tests_test_basic_c_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_basic_c_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_basic_c_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_test_bloom_OBJECTS = \ + src/libostree/tests_test_bloom-ostree-bloom.$(OBJEXT) \ + tests/test_bloom-test-bloom.$(OBJEXT) +tests_test_bloom_OBJECTS = $(am_tests_test_bloom_OBJECTS) +tests_test_bloom_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_bloom_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_bloom_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +tests_test_bsdiff_SOURCES = tests/test-bsdiff.c +tests_test_bsdiff_OBJECTS = tests/test_bsdiff-test-bsdiff.$(OBJEXT) +tests_test_bsdiff_DEPENDENCIES = libbsdiff.la $(am__DEPENDENCIES_14) +tests_test_bsdiff_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_bsdiff_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +am_tests_test_checksum_OBJECTS = \ + src/libostree/tests_test_checksum-ostree-core.$(OBJEXT) \ + src/libostree/tests_test_checksum-ostree-varint.$(OBJEXT) \ + tests/test_checksum-test-checksum.$(OBJEXT) +tests_test_checksum_OBJECTS = $(am_tests_test_checksum_OBJECTS) +tests_test_checksum_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_checksum_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_checksum_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__tests_test_gpg_verify_result_SOURCES_DIST = \ + src/libostree/ostree-gpg-verify-result-private.h \ + tests/test-gpg-verify-result.c +@USE_GPGME_TRUE@am_tests_test_gpg_verify_result_OBJECTS = tests/test_gpg_verify_result-test-gpg-verify-result.$(OBJEXT) +tests_test_gpg_verify_result_OBJECTS = \ + $(am_tests_test_gpg_verify_result_OBJECTS) +@USE_GPGME_TRUE@tests_test_gpg_verify_result_DEPENDENCIES = \ +@USE_GPGME_TRUE@ $(am__DEPENDENCIES_14) $(am__DEPENDENCIES_3) +tests_test_gpg_verify_result_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_gpg_verify_result_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_test_include_ostree_h_OBJECTS = \ + tests/test_include_ostree_h-test-include-ostree-h.$(OBJEXT) +tests_test_include_ostree_h_OBJECTS = \ + $(am_tests_test_include_ostree_h_OBJECTS) +tests_test_include_ostree_h_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_include_ostree_h_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_include_ostree_h_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_test_kargs_OBJECTS = \ + src/libostree/tests_test_kargs-ostree-kernel-args.$(OBJEXT) \ + tests/test_kargs-test-kargs.$(OBJEXT) +tests_test_kargs_OBJECTS = $(am_tests_test_kargs_OBJECTS) +tests_test_kargs_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_kargs_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_kargs_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +tests_test_keyfile_utils_SOURCES = tests/test-keyfile-utils.c +tests_test_keyfile_utils_OBJECTS = \ + tests/test_keyfile_utils-test-keyfile-utils.$(OBJEXT) +tests_test_keyfile_utils_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_keyfile_utils_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_keyfile_utils_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_test_libarchive_import_OBJECTS = \ + tests/test_libarchive_import-test-libarchive-import.$(OBJEXT) +tests_test_libarchive_import_OBJECTS = \ + $(am_tests_test_libarchive_import_OBJECTS) +tests_test_libarchive_import_DEPENDENCIES = $(am__DEPENDENCIES_14) \ + $(am__DEPENDENCIES_1) +tests_test_libarchive_import_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_libarchive_import_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_test_lzma_OBJECTS = \ + src/libostree/tests_test_lzma-ostree-lzma-common.$(OBJEXT) \ + src/libostree/tests_test_lzma-ostree-lzma-compressor.$(OBJEXT) \ + src/libostree/tests_test_lzma-ostree-lzma-decompressor.$(OBJEXT) \ + tests/test_lzma-test-lzma.$(OBJEXT) +tests_test_lzma_OBJECTS = $(am_tests_test_lzma_OBJECTS) +tests_test_lzma_DEPENDENCIES = $(am__DEPENDENCIES_14) \ + $(am__DEPENDENCIES_1) +tests_test_lzma_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_lzma_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +tests_test_mutable_tree_SOURCES = tests/test-mutable-tree.c +tests_test_mutable_tree_OBJECTS = \ + tests/test_mutable_tree-test-mutable-tree.$(OBJEXT) +tests_test_mutable_tree_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_mutable_tree_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_mutable_tree_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +tests_test_ot_opt_utils_SOURCES = tests/test-ot-opt-utils.c +tests_test_ot_opt_utils_OBJECTS = \ + tests/test_ot_opt_utils-test-ot-opt-utils.$(OBJEXT) +tests_test_ot_opt_utils_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_ot_opt_utils_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_ot_opt_utils_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +tests_test_ot_tool_util_SOURCES = tests/test-ot-tool-util.c +tests_test_ot_tool_util_OBJECTS = \ + tests/test_ot_tool_util-test-ot-tool-util.$(OBJEXT) +tests_test_ot_tool_util_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_ot_tool_util_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_ot_tool_util_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +tests_test_ot_unix_utils_SOURCES = tests/test-ot-unix-utils.c +tests_test_ot_unix_utils_OBJECTS = \ + tests/test_ot_unix_utils-test-ot-unix-utils.$(OBJEXT) +tests_test_ot_unix_utils_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_ot_unix_utils_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_ot_unix_utils_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +tests_test_pull_c_SOURCES = tests/test-pull-c.c +tests_test_pull_c_OBJECTS = tests/test_pull_c-test-pull-c.$(OBJEXT) +tests_test_pull_c_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_pull_c_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_pull_c_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +tests_test_repo_SOURCES = tests/test-repo.c +tests_test_repo_OBJECTS = tests/test_repo-test-repo.$(OBJEXT) +tests_test_repo_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_repo_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_repo_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +am__tests_test_repo_finder_avahi_SOURCES_DIST = \ + src/libostree/ostree-repo-finder-avahi-parser.c \ + tests/test-repo-finder-avahi.c +@USE_AVAHI_TRUE@am_tests_test_repo_finder_avahi_OBJECTS = src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.$(OBJEXT) \ +@USE_AVAHI_TRUE@ tests/test_repo_finder_avahi-test-repo-finder-avahi.$(OBJEXT) +tests_test_repo_finder_avahi_OBJECTS = \ + $(am_tests_test_repo_finder_avahi_OBJECTS) +@USE_AVAHI_TRUE@tests_test_repo_finder_avahi_DEPENDENCIES = \ +@USE_AVAHI_TRUE@ $(am__DEPENDENCIES_14) +tests_test_repo_finder_avahi_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_test_repo_finder_config_OBJECTS = tests/test_repo_finder_config-test-repo-finder-config.$(OBJEXT) +tests_test_repo_finder_config_OBJECTS = \ + $(am_tests_test_repo_finder_config_OBJECTS) +tests_test_repo_finder_config_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_repo_finder_config_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_repo_finder_config_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +am_tests_test_repo_finder_mount_OBJECTS = \ + tests/test_repo_finder_mount-test-repo-finder-mount.$(OBJEXT) +tests_test_repo_finder_mount_OBJECTS = \ + $(am_tests_test_repo_finder_mount_OBJECTS) +tests_test_repo_finder_mount_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_repo_finder_mount_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_repo_finder_mount_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_test_rollsum_OBJECTS = \ + src/libostree/tests_test_rollsum-ostree-rollsum.$(OBJEXT) \ + tests/test_rollsum-test-rollsum.$(OBJEXT) +tests_test_rollsum_OBJECTS = $(am_tests_test_rollsum_OBJECTS) +tests_test_rollsum_DEPENDENCIES = $(bupsplitpath) \ + $(am__DEPENDENCIES_14) $(am__DEPENDENCIES_1) +tests_test_rollsum_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_rollsum_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_test_rollsum_cli_OBJECTS = \ + src/libostree/tests_test_rollsum_cli-ostree-rollsum.$(OBJEXT) \ + tests/test_rollsum_cli-test-rollsum-cli.$(OBJEXT) +tests_test_rollsum_cli_OBJECTS = $(am_tests_test_rollsum_cli_OBJECTS) +tests_test_rollsum_cli_DEPENDENCIES = $(bupsplitpath) \ + $(am__DEPENDENCIES_14) $(am__DEPENDENCIES_1) +tests_test_rollsum_cli_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +tests_test_sysroot_c_SOURCES = tests/test-sysroot-c.c +tests_test_sysroot_c_OBJECTS = \ + tests/test_sysroot_c-test-sysroot-c.$(OBJEXT) +tests_test_sysroot_c_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_sysroot_c_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_sysroot_c_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_tests_test_varint_OBJECTS = \ + src/libostree/tests_test_varint-ostree-varint.$(OBJEXT) \ + tests/test_varint-test-varint.$(OBJEXT) +tests_test_varint_OBJECTS = $(am_tests_test_varint_OBJECTS) +tests_test_varint_DEPENDENCIES = $(am__DEPENDENCIES_14) +tests_test_varint_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(tests_test_varint_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +SCRIPTS = $(bin_SCRIPTS) $(dracutmod_SCRIPTS) \ + $(installed_test_SCRIPTS) $(mkinitcpioinstall_SCRIPTS) \ + $(noinst_SCRIPTS) $(ostree_boot_SCRIPTS) $(pkglibexec_SCRIPTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Plo \ + bsdiff/$(DEPDIR)/libbsdiff_la-bspatch.Plo \ + libglnx/$(DEPDIR)/la-glnx-backports.Plo \ + libglnx/$(DEPDIR)/la-glnx-console.Plo \ + libglnx/$(DEPDIR)/la-glnx-dirfd.Plo \ + libglnx/$(DEPDIR)/la-glnx-errors.Plo \ + libglnx/$(DEPDIR)/la-glnx-fdio.Plo \ + libglnx/$(DEPDIR)/la-glnx-local-alloc.Plo \ + libglnx/$(DEPDIR)/la-glnx-lockfile.Plo \ + libglnx/$(DEPDIR)/la-glnx-shutil.Plo \ + libglnx/$(DEPDIR)/la-glnx-xattrs.Plo \ + libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Po \ + libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Po \ + libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Po \ + libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Po \ + libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Po \ + libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Po \ + libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Po \ + libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Po \ + libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Po \ + libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po \ + src/libostree/$(DEPDIR)/bupsplit.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-async-progress.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-bloom.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-grub2.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-syslinux.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-uboot.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-zipl.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-chain-input-stream.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-checksum-input-stream.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-cmdprivate.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-core.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-deployment.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-diff.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-dummy-enumtypes.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-curl.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-soup.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-uri.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-util.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verifier.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result-dummy.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-kernel-args.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-libarchive-input-stream.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-linuxfsutil.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-common.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-compressor.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-decompressor.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-metalink.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-mutable-tree.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-ref.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-checkout.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-commit.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file-enumerator.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-config.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-mount.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-core.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-processing.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-traverse.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-deploy.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-upgrader.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-tls-cert-interaction.Plo \ + src/libostree/$(DEPDIR)/libostree_1_la-ostree-varint.Plo \ + src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Po \ + src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Po \ + src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Po \ + src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Po \ + src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Po \ + src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Po \ + src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Po \ + src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Po \ + src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Po \ + src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Po \ + src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Po \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-instream.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-utils.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-fs-utils.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-keyfile-utils.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Plo \ + src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-utils.Plo \ + src/ostree/$(DEPDIR)/ostree-main.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Po \ + src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po \ + src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po \ + src/ostree/$(DEPDIR)/ostree-ot-dump.Po \ + src/ostree/$(DEPDIR)/ostree-ot-editor.Po \ + src/ostree/$(DEPDIR)/ostree-ot-main.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Po \ + src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Po \ + src/ostree/$(DEPDIR)/ostree-parse-datetime.Po \ + src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Po \ + src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Po \ + src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Po \ + src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Po \ + src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Po \ + tests/$(DEPDIR)/get_byte_order-get-byte-order.Po \ + tests/$(DEPDIR)/libostreetest_la-libostreetest.Plo \ + tests/$(DEPDIR)/libostreetest_la-test-mock-gio.Plo \ + tests/$(DEPDIR)/libreaddir_rand_la-readdir-rand.Plo \ + tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Po \ + tests/$(DEPDIR)/test_basic_c-test-basic-c.Po \ + tests/$(DEPDIR)/test_bloom-test-bloom.Po \ + tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Po \ + tests/$(DEPDIR)/test_checksum-test-checksum.Po \ + tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Po \ + tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Po \ + tests/$(DEPDIR)/test_kargs-test-kargs.Po \ + tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Po \ + tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Po \ + tests/$(DEPDIR)/test_lzma-test-lzma.Po \ + tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Po \ + tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Po \ + tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Po \ + tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Po \ + tests/$(DEPDIR)/test_pull_c-test-pull-c.Po \ + tests/$(DEPDIR)/test_repo-test-repo.Po \ + tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Po \ + tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Po \ + tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Po \ + tests/$(DEPDIR)/test_rollsum-test-rollsum.Po \ + tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Po \ + tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Po \ + tests/$(DEPDIR)/test_varint-test-varint.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libbsdiff_la_SOURCES) $(libbupsplit_la_SOURCES) \ + $(libglnx_la_SOURCES) $(libostree_1_la_SOURCES) \ + $(nodist_libostree_1_la_SOURCES) $(libostreetest_la_SOURCES) \ + $(libotutil_la_SOURCES) $(libreaddir_rand_la_SOURCES) \ + $(ostree_SOURCES) $(nodist_ostree_SOURCES) \ + $(ostree_prepare_root_SOURCES) $(ostree_remount_SOURCES) \ + $(ostree_system_generator_SOURCES) \ + $(ostree_trivial_httpd_SOURCES) $(rofiles_fuse_SOURCES) \ + $(test_libglnx_errors_SOURCES) $(test_libglnx_fdio_SOURCES) \ + $(test_libglnx_macros_SOURCES) $(test_libglnx_shutil_SOURCES) \ + $(test_libglnx_xattrs_SOURCES) $(tests_get_byte_order_SOURCES) \ + $(tests_repo_finder_mount_SOURCES) tests/test-basic-c.c \ + $(tests_test_bloom_SOURCES) tests/test-bsdiff.c \ + $(tests_test_checksum_SOURCES) \ + $(tests_test_gpg_verify_result_SOURCES) \ + $(tests_test_include_ostree_h_SOURCES) \ + $(tests_test_kargs_SOURCES) tests/test-keyfile-utils.c \ + $(tests_test_libarchive_import_SOURCES) \ + $(tests_test_lzma_SOURCES) tests/test-mutable-tree.c \ + tests/test-ot-opt-utils.c tests/test-ot-tool-util.c \ + tests/test-ot-unix-utils.c tests/test-pull-c.c \ + tests/test-repo.c $(tests_test_repo_finder_avahi_SOURCES) \ + $(tests_test_repo_finder_config_SOURCES) \ + $(tests_test_repo_finder_mount_SOURCES) \ + $(tests_test_rollsum_SOURCES) \ + $(tests_test_rollsum_cli_SOURCES) tests/test-sysroot-c.c \ + $(tests_test_varint_SOURCES) +DIST_SOURCES = $(libbsdiff_la_SOURCES) \ + $(am__libbupsplit_la_SOURCES_DIST) $(libglnx_la_SOURCES) \ + $(am__libostree_1_la_SOURCES_DIST) $(libostreetest_la_SOURCES) \ + $(am__libotutil_la_SOURCES_DIST) $(libreaddir_rand_la_SOURCES) \ + $(am__ostree_SOURCES_DIST) $(ostree_prepare_root_SOURCES) \ + $(ostree_remount_SOURCES) \ + $(am__ostree_system_generator_SOURCES_DIST) \ + $(am__ostree_trivial_httpd_SOURCES_DIST) \ + $(am__rofiles_fuse_SOURCES_DIST) \ + $(test_libglnx_errors_SOURCES) $(test_libglnx_fdio_SOURCES) \ + $(test_libglnx_macros_SOURCES) $(test_libglnx_shutil_SOURCES) \ + $(test_libglnx_xattrs_SOURCES) $(tests_get_byte_order_SOURCES) \ + $(tests_repo_finder_mount_SOURCES) tests/test-basic-c.c \ + $(tests_test_bloom_SOURCES) tests/test-bsdiff.c \ + $(tests_test_checksum_SOURCES) \ + $(am__tests_test_gpg_verify_result_SOURCES_DIST) \ + $(tests_test_include_ostree_h_SOURCES) \ + $(tests_test_kargs_SOURCES) tests/test-keyfile-utils.c \ + $(tests_test_libarchive_import_SOURCES) \ + $(tests_test_lzma_SOURCES) tests/test-mutable-tree.c \ + tests/test-ot-opt-utils.c tests/test-ot-tool-util.c \ + tests/test-ot-unix-utils.c tests/test-pull-c.c \ + tests/test-repo.c \ + $(am__tests_test_repo_finder_avahi_SOURCES_DIST) \ + $(tests_test_repo_finder_config_SOURCES) \ + $(tests_test_repo_finder_mount_SOURCES) \ + $(tests_test_rollsum_SOURCES) \ + $(tests_test_rollsum_cli_SOURCES) tests/test-sysroot-c.c \ + $(tests_test_varint_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +man1dir = $(mandir)/man1 +man5dir = $(mandir)/man5 +NROFF = nroff +MANS = $(man1_MANS) $(man5_MANS) +am__dist_gpginsttest_DATA_DIST = tests/gpghome/secring.gpg \ + tests/gpghome/pubring.gpg tests/gpghome/trustdb.gpg \ + tests/gpghome/key1.asc tests/gpghome/key2.asc \ + tests/gpghome/key3.asc +am__dist_gpginsttest_revoc_DATA_DIST = \ + tests/gpghome/revocations/key1.rev \ + tests/gpghome/revocations/key2.rev \ + tests/gpghome/revocations/key3.rev +am__dist_gpginsttest_trusted_DATA_DIST = \ + tests/gpghome/trusted/pubring.gpg +am__dist_gpgvinsttest_DATA_DIST = $(addprefix tests/gpg-verify-data/, \ + gpg.conf lgpl2 lgpl2.sig lgpl2.sig0 lgpl2.sig1 lgpl2.sig2 \ + lgpl2.sig3 lgpl2.sig4 pubring.gpg secring.gpg trustdb.gpg) +am__dist_systemdtmpfiles_DATA_DIST = src/boot/ostree-tmpfiles.conf +DATA = $(dist_completions_DATA) $(dist_gpginsttest_DATA) \ + $(dist_gpginsttest_revoc_DATA) \ + $(dist_gpginsttest_trusted_DATA) $(dist_gpgvinsttest_DATA) \ + $(dist_systemdtmpfiles_DATA) $(dracutconf_DATA) $(gir_DATA) \ + $(gpgreadme_DATA) $(installed_test_DATA) \ + $(installed_test_meta_DATA) $(mkinitcpioconf_DATA) \ + $(nobase_installed_test_DATA) $(noinst_DATA) $(pkgconfig_DATA) \ + $(systemdsystemunit_DATA) $(typelib_DATA) +HEADERS = $(libostreeinclude_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope check recheck distdir distdir-am dist dist-all \ + distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ + $(LISP)config.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +RECHECK_LOGS = $(TEST_LOGS) +@USE_GPGME_TRUE@am__EXEEXT_20 = tests/test-remote-gpg-import.sh \ +@USE_GPGME_TRUE@ tests/test-gpg-signed-commit.sh \ +@USE_GPGME_TRUE@ tests/test-admin-gpg.sh $(am__EXEEXT_2) +am__EXEEXT_21 = $(am__EXEEXT_2) +@ENABLE_EXPERIMENTAL_API_TRUE@am__EXEEXT_22 = $(am__EXEEXT_21) +am__EXEEXT_23 = tests/test-core.js tests/test-remotes-config-dir.js \ + tests/test-sizes.js tests/test-sysroot.js $(am__EXEEXT_2) +@BUILDOPT_GJS_TRUE@am__EXEEXT_24 = $(js_tests) $(am__EXEEXT_23) +am__EXEEXT_25 = tests/test-basic.sh tests/test-basic-user.sh \ + tests/test-basic-user-only.sh tests/test-basic-root.sh \ + tests/test-pull-subpath.sh tests/test-archivez.sh \ + tests/test-remote-add.sh tests/test-remote-headers.sh \ + tests/test-commit-sign.sh tests/test-export.sh \ + tests/test-help.sh tests/test-libarchive.sh \ + tests/test-parent.sh tests/test-pull-bare.sh \ + tests/test-pull-bareuser.sh tests/test-pull-bareuseronly.sh \ + tests/test-pull2-bareuseronly.sh \ + tests/test-pull-commit-only.sh tests/test-pull-depth.sh \ + tests/test-pull-mirror-summary.sh \ + tests/test-pull-large-metadata.sh tests/test-pull-metalink.sh \ + tests/test-pull-summary-sigs.sh tests/test-pull-resume.sh \ + tests/test-pull-basicauth.sh tests/test-pull-repeated.sh \ + tests/test-pull-sizes.sh tests/test-pull-untrusted.sh \ + tests/test-pull-override-url.sh tests/test-pull-localcache.sh \ + tests/test-local-pull.sh tests/test-local-pull-depth.sh \ + tests/test-admin-upgrade-unconfigured.sh \ + tests/test-admin-upgrade-endoflife.sh \ + tests/test-admin-upgrade-systemd-update.sh \ + tests/test-admin-deploy-syslinux.sh \ + tests/test-admin-deploy-2.sh tests/test-admin-deploy-karg.sh \ + tests/test-admin-deploy-switch.sh \ + tests/test-admin-deploy-etcmerge-cornercases.sh \ + tests/test-admin-deploy-uboot.sh \ + tests/test-admin-deploy-grub2.sh \ + tests/test-admin-deploy-nomerge.sh \ + tests/test-admin-deploy-none.sh \ + tests/test-admin-deploy-bootid-gc.sh \ + tests/test-admin-instutil-set-kargs.sh \ + tests/test-admin-upgrade-not-backwards.sh \ + tests/test-admin-pull-deploy-commit.sh \ + tests/test-admin-pull-deploy-split.sh \ + tests/test-admin-locking.sh tests/test-admin-deploy-clean.sh \ + tests/test-reset-nonlinear.sh tests/test-oldstyle-partial.sh \ + tests/test-delta.sh tests/test-xattrs.sh \ + tests/test-auto-summary.sh tests/test-prune.sh \ + tests/test-concurrency.py tests/test-refs.sh \ + tests/test-demo-buildsystem.sh tests/test-switchroot.sh \ + tests/test-pull-contenturl.sh tests/test-pull-mirrorlist.sh \ + tests/test-summary-update.sh tests/test-summary-view.sh \ + tests/test-no-initramfs.sh tests/test-create-usb.sh \ + tests/test-find-remotes.sh tests/test-fsck-collections.sh \ + tests/test-fsck-delete.sh tests/test-init-collections.sh \ + tests/test-prune-collections.sh tests/test-refs-collections.sh \ + tests/test-remote-add-collections.sh \ + tests/test-repo-finder-mount-integration.sh \ + tests/test-summary-collections.sh \ + tests/test-pull-collections.sh tests/test-config.sh \ + tests/test-signed-commit.sh tests/test-signed-pull.sh \ + tests/test-pre-signed-pull.sh \ + tests/test-signed-pull-summary.sh $(am__EXEEXT_2) \ + $(am__EXEEXT_20) $(am__EXEEXT_22) $(am__append_79) \ + $(am__append_82) $(am__EXEEXT_24) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__EXEEXT_26 = \ +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@ $(am__EXEEXT_25) +am__EXEEXT_27 = $(am__EXEEXT_2) $(am__EXEEXT_26) +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +DIST_SUBDIRS = . apidoc +am__DIST_COMMON = $(srcdir)/Makefile-bash.am \ + $(srcdir)/Makefile-boot.am $(srcdir)/Makefile-decls.am \ + $(srcdir)/Makefile-libostree-defines.am \ + $(srcdir)/Makefile-libostree.am $(srcdir)/Makefile-man.am \ + $(srcdir)/Makefile-ostree.am $(srcdir)/Makefile-otutil.am \ + $(srcdir)/Makefile-switchroot.am $(srcdir)/Makefile-tests.am \ + $(srcdir)/Makefile.in $(srcdir)/bsdiff/Makefile-bsdiff.am.inc \ + $(srcdir)/config.h.in \ + $(srcdir)/libglnx/Makefile-libglnx.am.inc \ + $(srcdir)/src/rofiles-fuse/Makefile-inc.am \ + $(top_srcdir)/build-aux/compile \ + $(top_srcdir)/build-aux/config.guess \ + $(top_srcdir)/build-aux/config.sub \ + $(top_srcdir)/build-aux/depcomp \ + $(top_srcdir)/build-aux/install-sh \ + $(top_srcdir)/build-aux/ltmain.sh \ + $(top_srcdir)/build-aux/missing \ + $(top_srcdir)/build-aux/test-driver \ + $(top_srcdir)/buildutil/glib-tap.mk \ + $(top_srcdir)/src/libostree/ostree-1.pc.in \ + $(top_srcdir)/src/libostree/ostree-version.h.in COPYING TODO \ + build-aux/compile build-aux/config.guess build-aux/config.sub \ + build-aux/depcomp build-aux/install-sh build-aux/ltmain.sh \ + build-aux/missing +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +GZIP_ENV = --best +DIST_ARCHIVES = $(distdir).tar.xz +DIST_TARGETS = dist-xz +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASH_COMPLETIONSDIR = @BASH_COMPLETIONSDIR@ +BUILDOPT_FUSE_CFLAGS = @BUILDOPT_FUSE_CFLAGS@ +BUILDOPT_FUSE_LIBS = @BUILDOPT_FUSE_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GJS = @GJS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GPGME_CONFIG = @GPGME_CONFIG@ +GPGME_PTHREAD_CFLAGS = @GPGME_PTHREAD_CFLAGS@ +GPGME_PTHREAD_LIBS = @GPGME_PTHREAD_LIBS@ +GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@ +GREP = @GREP@ +GRUB2_MKCONFIG = @GRUB2_MKCONFIG@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ +LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OSTREE_FEATURES = @OSTREE_FEATURES@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +OT_DEP_AVAHI_CFLAGS = @OT_DEP_AVAHI_CFLAGS@ +OT_DEP_AVAHI_LIBS = @OT_DEP_AVAHI_LIBS@ +OT_DEP_CRYPTO_CFLAGS = @OT_DEP_CRYPTO_CFLAGS@ +OT_DEP_CRYPTO_LIBS = @OT_DEP_CRYPTO_LIBS@ +OT_DEP_CURL_CFLAGS = @OT_DEP_CURL_CFLAGS@ +OT_DEP_CURL_LIBS = @OT_DEP_CURL_LIBS@ +OT_DEP_E2P_CFLAGS = @OT_DEP_E2P_CFLAGS@ +OT_DEP_E2P_LIBS = @OT_DEP_E2P_LIBS@ +OT_DEP_GIO_UNIX_CFLAGS = @OT_DEP_GIO_UNIX_CFLAGS@ +OT_DEP_GIO_UNIX_LIBS = @OT_DEP_GIO_UNIX_LIBS@ +OT_DEP_GPGME_CFLAGS = @OT_DEP_GPGME_CFLAGS@ +OT_DEP_GPGME_LIBS = @OT_DEP_GPGME_LIBS@ +OT_DEP_GPG_ERROR_CFLAGS = @OT_DEP_GPG_ERROR_CFLAGS@ +OT_DEP_GPG_ERROR_LIBS = @OT_DEP_GPG_ERROR_LIBS@ +OT_DEP_LIBARCHIVE_CFLAGS = @OT_DEP_LIBARCHIVE_CFLAGS@ +OT_DEP_LIBARCHIVE_LIBS = @OT_DEP_LIBARCHIVE_LIBS@ +OT_DEP_LIBMOUNT_CFLAGS = @OT_DEP_LIBMOUNT_CFLAGS@ +OT_DEP_LIBMOUNT_LIBS = @OT_DEP_LIBMOUNT_LIBS@ +OT_DEP_LIBSODIUM_CFLAGS = @OT_DEP_LIBSODIUM_CFLAGS@ +OT_DEP_LIBSODIUM_LIBS = @OT_DEP_LIBSODIUM_LIBS@ +OT_DEP_LZMA_CFLAGS = @OT_DEP_LZMA_CFLAGS@ +OT_DEP_LZMA_LIBS = @OT_DEP_LZMA_LIBS@ +OT_DEP_SELINUX_CFLAGS = @OT_DEP_SELINUX_CFLAGS@ +OT_DEP_SELINUX_LIBS = @OT_DEP_SELINUX_LIBS@ +OT_DEP_SOUP_CFLAGS = @OT_DEP_SOUP_CFLAGS@ +OT_DEP_SOUP_LIBS = @OT_DEP_SOUP_LIBS@ +OT_DEP_ZLIB_CFLAGS = @OT_DEP_ZLIB_CFLAGS@ +OT_DEP_ZLIB_LIBS = @OT_DEP_ZLIB_LIBS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE_VERSION = @RELEASE_VERSION@ +RUST_TARGET_SUBDIR = @RUST_TARGET_SUBDIR@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STATIC_COMPILER = @STATIC_COMPILER@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XSLTPROC = @XSLTPROC@ +YACC = @YACC@ +YEAR_VERSION = @YEAR_VERSION@ +YFLAGS = @YFLAGS@ +_GI_EXP_DATADIR = @_GI_EXP_DATADIR@ +_GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cargo = @cargo@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +installed_test_metadir = @installed_test_metadir@ +installed_testdir = @installed_testdir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rustc = @rustc@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemdsystemgeneratordir = @systemdsystemgeneratordir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Common variables +AM_CPPFLAGS = -DDATADIR='"$(datadir)"' -DLIBEXECDIR='"$(libexecdir)"' \ + -DLOCALEDIR=\"$(datadir)/locale\" \ + -DSYSCONFDIR=\"$(sysconfdir)\" -DTARGET_PREFIX='"$(prefix)"' \ + -DSHORTENED_SYSCONFDIR=\"$(shortened_sysconfdir)\" \ + -DOSTREE_FEATURES='"$(OSTREE_FEATURES)"' -DOSTREE_COMPILATION \ + -DG_LOG_DOMAIN=\"OSTree\" -DOSTREE_GITREV='"$(OSTREE_GITREV)"' \ + -DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_40 \ + '-DGLIB_VERSION_MAX_ALLOWED=G_ENCODE_VERSION(2,50)' \ + -DSOUP_VERSION_MIN_REQUIRED=SOUP_VERSION_2_40 \ + '-DSOUP_VERSION_MAX_ALLOWED=G_ENCODE_VERSION(2,48)' +# For strict aliasing, see https://bugzilla.gnome.org/show_bug.cgi?id=791622 +AM_CFLAGS = -std=gnu99 -fno-strict-aliasing $(WARN_CFLAGS) + +# Allow the distcheck install under $prefix test to pass +AM_DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-man \ + --disable-maintainer-mode $(NULL) $(am__append_73) \ + $(am__append_94) \ + BASH_COMPLETIONSDIR='$${datadir}/bash-completion/completions' +SUBDIRS = . $(am__append_14) +NULL = +BUILT_SOURCES = $(nodist_libostree_1_la_SOURCES) +MANPAGES = +CLEANFILES = $(am__append_13) $(BUILT_SOURCES) $(am__append_52) \ + src/ostree/parse-datetime.c tests/libreaddir-rand.so \ + tests/ostree-symlink-stamp \ + tests/ostree-prepare-root-symlink-stamp \ + tests/ostree-remount-symlink-stamp \ + tests/rofiles-fuse-symlink-stamp tests/ostree \ + tests/ostree-prepare-root tests/ostree-remount \ + tests/rofiles-fuse $(am__append_103) +EXTRA_DIST = $(all_dist_test_scripts) $(all_dist_test_data) autogen.sh \ + COPYING README.md $(am__append_15) libglnx/README.md \ + libglnx/COPYING libglnx/libglnx.m4 $(NULL) \ + libglnx/Makefile-libglnx.am bsdiff/bsdiff.h bsdiff/bspatch.h \ + bsdiff/LICENSE bsdiff/README.md bsdiff/Makefile-bsdiff.am \ + $(am__append_17) \ + $(top_srcdir)/src/libostree/libostree-devel.sym \ + $(top_srcdir)/src/libostree/libostree-released.sym $(NULL) \ + src/libostree/README-gpg src/libostree/bupsplit.h \ + src/libostree/ostree-enumtypes.h.template \ + src/libostree/ostree-enumtypes.c.template \ + src/libostree/ostree-deployment-private.h \ + src/libostree/ostree-repo-deprecated.h \ + src/libostree/ostree-version.h src/ostree/parse-datetime.y \ + buildutil/tap-driver.sh buildutil/tap-test tests/glib.supp \ + tests/ostree.supp $(NULL) $(am__append_78) $(am__append_81) \ + $(am__append_84) tests/libtest.sh $(am__append_85) \ + $(am__append_90) tests/libostreetest.h tests/libtest.sh \ + $(NULL) src/boot/dracut/module-setup.sh \ + src/boot/dracut/ostree.conf src/boot/mkinitcpio/ostree \ + src/boot/ostree-prepare-root.service \ + src/boot/ostree-finalize-staged.path \ + src/boot/ostree-remount.service \ + src/boot/ostree-finalize-staged.service \ + src/boot/grub2/grub2-15_ostree \ + src/boot/grub2/ostree-grub-generator $(NULL) $(am__append_99) \ + $(am__append_102) +bin_SCRIPTS = +lib_LTLIBRARIES = libostree-1.la +pkglibexec_SCRIPTS = $(am__append_95) +noinst_LTLIBRARIES = $(am__append_1) libglnx.la libbsdiff.la \ + libotutil.la $(am__append_18) libostreetest.la +privlibdir = $(pkglibdir) +privlib_LTLIBRARIES = +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = src/libostree/ostree-1.pc +INTROSPECTION_GIRS = $(am__append_49) +girdir = $(datadir)/gir-1.0 +gir_DATA = $(am__append_50) +typelibdir = $(libdir)/girepository-1.0 +typelib_DATA = $(am__append_51) +gsettings_SCHEMAS = +ostree_bootdir = $(prefix)/lib/ostree +ostree_boot_SCRIPTS = $(am__append_67) $(am__append_97) + +# We should probably consider flipping the default for DEBUG. Also, +# include the builddir in $PATH so we find our just-built ostree +# binary. +AM_TESTS_ENVIRONMENT = G_TEST_SRCDIR="$(abs_srcdir)" \ + G_TEST_BUILDDIR="$(abs_builddir)" UNINSTALLEDTESTS=1 \ + G_DEBUG=gc-friendly MALLOC_CHECK_=2 \ + MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) OT_TESTS_DEBUG=1 \ + OSTREE_UNINSTALLED_SRCDIR=$(abs_top_srcdir) \ + OSTREE_UNINSTALLED=$(abs_top_builddir) G_DEBUG=fatal-warnings \ + GI_TYPELIB_PATH=$$(cd $(top_builddir) && \ + pwd)$${GI_TYPELIB_PATH:+:$$GI_TYPELIB_PATH} \ + LD_LIBRARY_PATH=$$(cd $(top_builddir)/.libs && \ + pwd)$${LD_LIBRARY_PATH:+:$${LD_LIBRARY_PATH}} PATH=$$(cd \ + $(top_builddir)/tests && pwd):$${PATH} \ + OSTREE_FEATURES="$(OSTREE_FEATURES)" PYTHONUNBUFFERED=1 \ + $(NULL) $(am__append_75) +LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/buildutil/tap-driver.sh +LOG_COMPILER = $(top_srcdir)/buildutil/tap-test +installed_test_LTLIBRARIES = $(am__append_12) +installed_test_SCRIPTS = $(am__append_10) +installed_test_DATA = $(am__append_11) +nobase_installed_test_DATA = +noinst_SCRIPTS = $(am__append_3) +noinst_DATA = $(am__append_4) +check_LTLIBRARIES = $(am__append_5) +check_SCRIPTS = $(am__append_7) +check_DATA = $(am__append_8) + +# Note: build even the installed-only targets during 'make check' to ensure that they still work. +# We need to do a bit of trickery here and manage disting via EXTRA_DIST instead of using dist_ prefixes to +# prevent automake from mistreating gmake functions like $(wildcard ...) and $(addprefix ...) as if they were +# filenames, including removing duplicate instances of the opening part before the space, eg. '$(addprefix'. +all_test_programs = $(test_programs) $(uninstalled_test_programs) $(installed_test_programs) \ + $(test_extra_programs) $(uninstalled_test_extra_programs) $(installed_test_extra_programs) + +all_test_scripts = $(test_scripts) $(uninstalled_test_scripts) \ + $(installed_test_scripts) $(test_extra_scripts) \ + $(uninstalled_test_extra_scripts) \ + $(installed_test_extra_scripts) $(all_dist_test_scripts) +all_dist_test_scripts = $(dist_test_scripts) $(dist_uninstalled_test_scripts) $(dist_installed_test_scripts) \ + $(dist_test_extra_scripts) $(dist_uninstalled_test_extra_scripts) $(dist_installed_test_extra_scripts) + +all_test_data = $(test_data) $(uninstalled_test_data) \ + $(installed_test_data) $(all_dist_test_data) +all_dist_test_data = $(dist_test_data) $(dist_uninstalled_test_data) $(dist_installed_test_data) +all_test_ltlibs = $(test_ltlibraries) $(uninstalled_test_ltlibraries) $(installed_test_ltlibraries) +@ENABLE_INSTALLED_TESTS_TRUE@installed_testcases = $(test_programs) $(installed_test_programs) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(test_scripts) $(installed_test_scripts) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(dist_test_scripts) $(dist_installed_test_scripts) + +@ENABLE_INSTALLED_TESTS_TRUE@installed_test_meta_DATA = $(installed_testcases:=.test) + +# This initializes some more variables + +# This is a special facility to chain together hooks easily +INSTALL_DATA_HOOKS = install-mkdir-remotes-d-hook $(am__append_93) \ + $(am__append_96) +ALL_LOCAL_RULES = tests/libreaddir-rand.so +shortened_sysconfdir = $$(echo "$(sysconfdir)" | sed -e 's|^$(prefix)||' -e 's|^/||') +OSTREE_GITREV = $(shell cd $(srcdir) && if command -v git >/dev/null 2>&1 && test -d .git; then git describe --abbrev=42 --tags --always HEAD; fi) +ACLOCAL_AMFLAGS = -I buildutil -I libglnx ${ACLOCAL_FLAGS} +GITIGNOREFILES = aclocal.m4 build-aux/ buildutil/*.m4 config.h.in \ + gtk-doc.make $(am__append_72) +OT_INTERNAL_GIO_UNIX_CFLAGS = $(OT_DEP_GIO_UNIX_CFLAGS) +OT_INTERNAL_GIO_UNIX_LIBS = $(OT_DEP_GIO_UNIX_LIBS) +OT_INTERNAL_SOUP_CFLAGS = $(OT_DEP_SOUP_CFLAGS) +OT_INTERNAL_SOUP_LIBS = $(OT_DEP_SOUP_LIBS) + +# This canonicalizes the PKG_CHECK_MODULES or AM_PATH_GPGME results +@USE_GPGME_TRUE@OT_INTERNAL_GPGME_CFLAGS = $(OT_DEP_GPGME_CFLAGS) $(GPGME_PTHREAD_CFLAGS) +@USE_GPGME_TRUE@OT_INTERNAL_GPGME_LIBS = $(OT_DEP_GPGME_LIBS) $(GPGME_PTHREAD_LIBS) +@BUILDOPT_INTROSPECTION_TRUE@GIRS = +@BUILDOPT_INTROSPECTION_TRUE@TYPELIBS = $(GIRS:.gir=.typelib) +@ENABLE_RUST_TRUE@@RUST_DEBUG_FALSE@CARGO_RELEASE_ARGS = --release + +# These bits based on gnome:librsvg/Makefile.am +@ENABLE_RUST_TRUE@@RUST_DEBUG_TRUE@CARGO_RELEASE_ARGS = +libglnx_srcpath := $(srcdir)/libglnx +libglnx_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(libglnx_srcpath)" +libglnx_libs := $(OT_DEP_GIO_UNIX_LIBS) +libglnx_la_SOURCES = \ + libglnx/glnx-macros.h \ + libglnx/glnx-backport-autocleanups.h \ + libglnx/glnx-backport-autoptr.h \ + libglnx/glnx-backports.h \ + libglnx/glnx-backports.c \ + libglnx/glnx-local-alloc.h \ + libglnx/glnx-local-alloc.c \ + libglnx/glnx-errors.h \ + libglnx/glnx-errors.c \ + libglnx/glnx-console.h \ + libglnx/glnx-console.c \ + libglnx/glnx-dirfd.h \ + libglnx/glnx-dirfd.c \ + libglnx/glnx-fdio.h \ + libglnx/glnx-fdio.c \ + libglnx/glnx-lockfile.h \ + libglnx/glnx-lockfile.c \ + libglnx/glnx-missing-syscall.h \ + libglnx/glnx-missing.h \ + libglnx/glnx-xattrs.h \ + libglnx/glnx-xattrs.c \ + libglnx/glnx-shutil.h \ + libglnx/glnx-shutil.c \ + libglnx/libglnx.h \ + libglnx/tests/libglnx-testlib.h \ + $(NULL) + +libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic +libglnx_la_LIBADD = $(libglnx_libs) +libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros test-libglnx-shutil +libglnx_testlib_sources = libglnx/tests/libglnx-testlib.c +test_libglnx_xattrs_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-xattrs.c +test_libglnx_xattrs_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_xattrs_LDADD = $(libglnx_libs) libglnx.la +test_libglnx_fdio_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-fdio.c +test_libglnx_fdio_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_fdio_LDADD = $(libglnx_libs) libglnx.la +test_libglnx_errors_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-errors.c +test_libglnx_errors_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_errors_LDADD = $(libglnx_libs) libglnx.la +test_libglnx_macros_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-macros.c +test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la +test_libglnx_shutil_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-shutil.c +test_libglnx_shutil_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_shutil_LDADD = $(libglnx_libs) libglnx.la +libbsdiff_srcpath := $(srcdir)/bsdiff +libbsdiff_cflags := $(OT_DEP_GIO_UNIX_CFLAGS) "-I$(bsdiff_srcpath)" +libbsdiff_libs := $(OT_DEP_GIO_UNIX_LIBS) +libbsdiff_la_SOURCES = \ + bsdiff/bsdiff.c \ + bsdiff/bspatch.c \ + $(NULL) + +libbsdiff_la_CFLAGS = $(AM_CFLAGS) +libotutil_la_SOURCES = src/libotutil/ot-checksum-utils.c \ + src/libotutil/ot-checksum-utils.h \ + src/libotutil/ot-checksum-instream.c \ + src/libotutil/ot-checksum-instream.h \ + src/libotutil/ot-fs-utils.c src/libotutil/ot-fs-utils.h \ + src/libotutil/ot-keyfile-utils.c \ + src/libotutil/ot-keyfile-utils.h src/libotutil/ot-opt-utils.c \ + src/libotutil/ot-opt-utils.h src/libotutil/ot-unix-utils.c \ + src/libotutil/ot-unix-utils.h src/libotutil/ot-variant-utils.c \ + src/libotutil/ot-variant-utils.h \ + src/libotutil/ot-variant-builder.c \ + src/libotutil/ot-variant-builder.h \ + src/libotutil/ot-gio-utils.c src/libotutil/ot-gio-utils.h \ + src/libotutil/otutil.h src/libotutil/ot-tool-util.c \ + src/libotutil/ot-tool-util.h $(NULL) $(am__append_16) +libotutil_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libotutil -DLOCALEDIR=\"$(datadir)/locale\" $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) $(LIBSYSTEMD_CFLAGS) +libotutil_la_LIBADD = $(OT_INTERNAL_GIO_UNIX_LIBS) $(OT_INTERNAL_GPGME_LIBS) $(LIBSYSTEMD_LIBS) +libostree_public_headers = \ + src/libostree/ostree.h \ + src/libostree/ostree-async-progress.h \ + src/libostree/ostree-autocleanups.h \ + src/libostree/ostree-core.h \ + src/libostree/ostree-dummy-enumtypes.h \ + src/libostree/ostree-mutable-tree.h \ + src/libostree/ostree-repo.h \ + src/libostree/ostree-types.h \ + src/libostree/ostree-repo-file.h \ + src/libostree/ostree-diff.h \ + src/libostree/ostree-gpg-verify-result.h \ + src/libostree/ostree-sepolicy.h \ + src/libostree/ostree-sysroot.h \ + src/libostree/ostree-sysroot-upgrader.h \ + src/libostree/ostree-deployment.h \ + src/libostree/ostree-bootconfig-parser.h \ + src/libostree/ostree-repo-deprecated.h \ + src/libostree/ostree-ref.h \ + src/libostree/ostree-remote.h \ + src/libostree/ostree-repo-finder.h \ + src/libostree/ostree-repo-finder-avahi.h \ + src/libostree/ostree-repo-finder-config.h \ + src/libostree/ostree-repo-finder-mount.h \ + src/libostree/ostree-repo-finder-override.h \ + src/libostree/ostree-kernel-args.h \ + src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-ed25519.h \ + $(NULL) + + +# This one is generated via configure.ac, and the gtk-doc +# code hence needs to look in the builddir. +libostree_public_built_headers = src/libostree/ostree-version.h +@ENABLE_RUST_FALSE@bupsplitpath = libbupsplit.la +@ENABLE_RUST_TRUE@bupsplitpath = @abs_top_builddir@/target/@RUST_TARGET_SUBDIR@/libbupsplit_rs.a +@ENABLE_RUST_TRUE@BUPSPLIT_RUST_SRCS = rust/src/bupsplit.rs +@ENABLE_RUST_FALSE@libbupsplit_la_SOURCES = src/libostree/bupsplit.h src/libostree/bupsplit.c +libostreeincludedir = $(includedir)/ostree-1 +libostreeinclude_HEADERS = $(libostree_public_headers) $(libostree_public_built_headers) +ENUM_TYPES = $(NULL) $(srcdir)/src/libostree/ostree-fetcher.h +nodist_libostree_1_la_SOURCES = \ + src/libostree/ostree-enumtypes.h \ + src/libostree/ostree-enumtypes.c \ + $(NULL) + +libostree_1_la_SOURCES = src/libostree/ostree-async-progress.c \ + src/libostree/ostree-cmdprivate.h \ + src/libostree/ostree-cmdprivate.c \ + src/libostree/ostree-core-private.h \ + src/libostree/ostree-core.c \ + src/libostree/ostree-dummy-enumtypes.c \ + src/libostree/ostree-checksum-input-stream.c \ + src/libostree/ostree-checksum-input-stream.h \ + src/libostree/ostree-chain-input-stream.c \ + src/libostree/ostree-chain-input-stream.h \ + src/libostree/ostree-lzma-common.c \ + src/libostree/ostree-lzma-common.h \ + src/libostree/ostree-lzma-compressor.c \ + src/libostree/ostree-lzma-compressor.h \ + src/libostree/ostree-lzma-decompressor.c \ + src/libostree/ostree-lzma-decompressor.h \ + src/libostree/ostree-rollsum.h src/libostree/ostree-rollsum.c \ + src/libostree/ostree-varint.h src/libostree/ostree-varint.c \ + src/libostree/ostree-linuxfsutil.h \ + src/libostree/ostree-linuxfsutil.c src/libostree/ostree-diff.c \ + src/libostree/ostree-mutable-tree.c src/libostree/ostree-ref.c \ + src/libostree/ostree-remote.c \ + src/libostree/ostree-remote-private.h \ + src/libostree/ostree-repo.c \ + src/libostree/ostree-repo-checkout.c \ + src/libostree/ostree-repo-commit.c \ + src/libostree/ostree-repo-pull.c \ + src/libostree/ostree-repo-pull-private.h \ + src/libostree/ostree-repo-pull-verify.c \ + src/libostree/ostree-repo-libarchive.c \ + src/libostree/ostree-repo-prune.c \ + src/libostree/ostree-repo-refs.c \ + src/libostree/ostree-repo-traverse.c \ + src/libostree/ostree-repo-private.h \ + src/libostree/ostree-repo-file.c \ + src/libostree/ostree-repo-file-enumerator.c \ + src/libostree/ostree-repo-file-enumerator.h \ + src/libostree/ostree-sepolicy.c \ + src/libostree/ostree-sepolicy-private.h \ + src/libostree/ostree-sysroot-private.h \ + src/libostree/ostree-sysroot.c \ + src/libostree/ostree-sysroot-cleanup.c \ + src/libostree/ostree-sysroot-deploy.c \ + src/libostree/ostree-sysroot-upgrader.c \ + src/libostree/ostree-impl-system-generator.c \ + src/libostree/ostree-bootconfig-parser.c \ + src/libostree/ostree-deployment.c \ + src/libostree/ostree-bootloader.h \ + src/libostree/ostree-bootloader.c \ + src/libostree/ostree-bootloader-grub2.h \ + src/libostree/ostree-bootloader-grub2.c \ + src/libostree/ostree-bootloader-zipl.h \ + src/libostree/ostree-bootloader-zipl.c \ + src/libostree/ostree-bootloader-syslinux.h \ + src/libostree/ostree-bootloader-syslinux.c \ + src/libostree/ostree-bootloader-uboot.h \ + src/libostree/ostree-bootloader-uboot.c \ + src/libostree/ostree-repo-static-delta-core.c \ + src/libostree/ostree-repo-static-delta-processing.c \ + src/libostree/ostree-repo-static-delta-compilation.c \ + src/libostree/ostree-repo-static-delta-compilation-analysis.c \ + src/libostree/ostree-repo-static-delta-private.h \ + src/libostree/ostree-autocleanups.h \ + src/libostree/ostree-bloom.c \ + src/libostree/ostree-bloom-private.h \ + src/libostree/ostree-repo-finder.c \ + src/libostree/ostree-repo-finder-avahi.c \ + src/libostree/ostree-repo-finder-config.c \ + src/libostree/ostree-repo-finder-mount.c \ + src/libostree/ostree-repo-finder-override.c \ + src/libostree/ostree-kernel-args.h \ + src/libostree/ostree-kernel-args.c $(NULL) $(am__append_19) \ + $(am__append_20) $(am__append_21) $(am__append_22) \ + $(am__append_23) $(am__append_24) $(am__append_25) \ + $(am__append_34) $(am__append_35) $(am__append_38) \ + $(am__append_41) src/libostree/ostree-sign.c \ + src/libostree/ostree-sign.h src/libostree/ostree-sign-dummy.c \ + src/libostree/ostree-sign-dummy.h \ + src/libostree/ostree-sign-ed25519.c \ + src/libostree/ostree-sign-ed25519.h $(NULL) +libostree_experimental_headers = \ + $(NULL) + +symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym \ + $(am__append_26) +# http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html +wl_versionscript_arg = -Wl,--version-script= +libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/bsdiff \ + -I$(srcdir)/libglnx -I$(srcdir)/src/libotutil \ + -I$(srcdir)/src/libostree -I$(builddir)/src/libostree \ + $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) \ + $(OT_DEP_LZMA_CFLAGS) $(OT_DEP_ZLIB_CFLAGS) \ + $(OT_DEP_CRYPTO_CFLAGS) -fvisibility=hidden \ + '-D_OSTREE_PUBLIC=__attribute__((visibility("default"))) \ + extern' $(am__append_28) $(am__append_30) $(am__append_32) \ + $(am__append_36) $(am__append_39) $(am__append_42) \ + $(am__append_44) $(am__append_46) +libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions $(addprefix $(wl_versionscript_arg),$(symbol_files)) +libostree_1_la_LIBADD = libotutil.la libglnx.la libbsdiff.la \ + $(OT_INTERNAL_GIO_UNIX_LIBS) $(OT_INTERNAL_GPGME_LIBS) \ + $(OT_DEP_LZMA_LIBS) $(OT_DEP_ZLIB_LIBS) $(OT_DEP_CRYPTO_LIBS) \ + $(am__append_27) $(bupsplitpath) $(am__append_29) \ + $(am__append_31) $(am__append_33) $(am__append_37) \ + $(am__append_40) $(am__append_43) $(am__append_45) \ + $(am__append_47) +EXTRA_libostree_1_la_DEPENDENCIES = $(symbol_files) + +# XXX: work around clang being passed -fstack-clash-protection which it doesn't understand +# See: https://bugzilla.redhat.com/show_bug.cgi?id=1672012 +INTROSPECTION_SCANNER_ENV = CC=gcc +@BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_EXPORT_PACKAGES = ostree-1 +@BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_INCLUDES = Gio-2.0 +@BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_CFLAGS = \ +@BUILDOPT_INTROSPECTION_TRUE@ $(libostree_1_la_CFLAGS) \ +@BUILDOPT_INTROSPECTION_TRUE@ $(am__append_48) +@BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_LIBS = libostree-1.la +@BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_SCANNERFLAGS = --warn-all --identifier-prefix=Ostree --symbol-prefix=ostree $(GI_SCANNERFLAGS) +@BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_FILES = $(libostreeinclude_HEADERS) $(filter-out %-private.h %/ostree-soup-uri.h $(libostree_experimental_headers),$(libostree_1_la_SOURCES)) +gpgreadme_DATA = src/libostree/README-gpg +gpgreadmedir = $(datadir)/ostree/trusted.gpg.d + +# Admin subcommand + +# Remote subcommand +ostree_SOURCES = src/ostree/main.c src/ostree/ot-builtin-admin.c \ + src/ostree/ot-builtins.h src/ostree/ot-builtin-cat.c \ + src/ostree/ot-builtin-config.c \ + src/ostree/ot-builtin-checkout.c \ + src/ostree/ot-builtin-checksum.c \ + src/ostree/ot-builtin-commit.c \ + src/ostree/ot-builtin-create-usb.c \ + src/ostree/ot-builtin-diff.c src/ostree/ot-builtin-export.c \ + src/ostree/ot-builtin-find-remotes.c \ + src/ostree/ot-builtin-fsck.c src/ostree/ot-builtin-init.c \ + src/ostree/ot-builtin-pull-local.c src/ostree/ot-builtin-log.c \ + src/ostree/ot-builtin-ls.c src/ostree/ot-builtin-prune.c \ + src/ostree/ot-builtin-refs.c src/ostree/ot-builtin-remote.c \ + src/ostree/ot-builtin-reset.c \ + src/ostree/ot-builtin-rev-parse.c src/ostree/ot-builtin-sign.c \ + src/ostree/ot-builtin-summary.c src/ostree/ot-builtin-show.c \ + src/ostree/ot-builtin-static-delta.c src/ostree/ot-main.h \ + src/ostree/ot-main.c src/ostree/ot-dump.h src/ostree/ot-dump.c \ + src/ostree/ot-editor.c src/ostree/ot-editor.h \ + src/ostree/parse-datetime.h $(NULL) $(am__append_53) \ + $(am__append_54) src/ostree/ot-admin-builtin-init-fs.c \ + src/ostree/ot-admin-builtin-diff.c \ + src/ostree/ot-admin-builtin-deploy.c \ + src/ostree/ot-admin-builtin-finalize-staged.c \ + src/ostree/ot-admin-builtin-undeploy.c \ + src/ostree/ot-admin-builtin-instutil.c \ + src/ostree/ot-admin-builtin-cleanup.c \ + src/ostree/ot-admin-builtin-os-init.c \ + src/ostree/ot-admin-builtin-set-origin.c \ + src/ostree/ot-admin-builtin-status.c \ + src/ostree/ot-admin-builtin-switch.c \ + src/ostree/ot-admin-builtin-pin.c \ + src/ostree/ot-admin-builtin-upgrade.c \ + src/ostree/ot-admin-builtin-unlock.c \ + src/ostree/ot-admin-builtins.h \ + src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c \ + src/ostree/ot-admin-instutil-builtin-set-kargs.c \ + src/ostree/ot-admin-instutil-builtin-grub2-generate.c \ + src/ostree/ot-admin-instutil-builtins.h \ + src/ostree/ot-admin-functions.h \ + src/ostree/ot-admin-functions.c $(NULL) \ + src/ostree/ot-remote-builtins.h \ + src/ostree/ot-remote-builtin-add.c \ + src/ostree/ot-remote-builtin-delete.c \ + src/ostree/ot-remote-builtin-list.c \ + src/ostree/ot-remote-builtin-show-url.c \ + src/ostree/ot-remote-builtin-refs.c \ + src/ostree/ot-remote-builtin-summary.c $(NULL) \ + $(am__append_55) $(am__append_56) $(am__append_57) +nodist_ostree_SOURCES = \ + src/ostree/parse-datetime.c \ + $(NULL) + +ostree_bin_shared_cflags = $(AM_CFLAGS) -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree \ + -I$(builddir)/src/libostree -I$(srcdir)/src/ostree -I$(srcdir)/libglnx $(OT_INTERNAL_GIO_UNIX_CFLAGS) \ + -DPKGLIBEXECDIR=\"$(pkglibexecdir)\" + +ostree_bin_shared_ldadd = $(AM_LDFLAGS) libglnx.la libotutil.la libostree-1.la \ + $(OT_INTERNAL_GIO_UNIX_LIBS) + +ostree_CFLAGS = $(ostree_bin_shared_cflags) $(am__append_59) \ + $(am__append_61) $(am__append_63) +ostree_LDADD = $(ostree_bin_shared_ldadd) libbsdiff.la \ + $(LIBSYSTEMD_LIBS) $(am__append_60) $(am__append_62) \ + $(am__append_64) +@USE_LIBSOUP_TRUE@ostree_trivial_httpd_SOURCES = src/ostree/ostree-trivial-httpd.c +@USE_LIBSOUP_TRUE@ostree_trivial_httpd_CFLAGS = $(ostree_bin_shared_cflags) $(OT_INTERNAL_SOUP_CFLAGS) +@USE_LIBSOUP_TRUE@ostree_trivial_httpd_LDADD = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_SOUP_LIBS) +ostree_prepare_root_SOURCES = \ + src/switchroot/ostree-mount-util.h \ + src/switchroot/ostree-prepare-root.c \ + $(NULL) + +ostree_prepare_root_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_69) \ + $(am__append_70) +@BUILDOPT_USE_STATIC_COMPILER_FALSE@ostree_prepare_root_CFLAGS = $(AM_CFLAGS) -Isrc/switchroot +ostree_remount_SOURCES = \ + src/switchroot/ostree-mount-util.h \ + src/switchroot/ostree-remount.c \ + $(NULL) + +ostree_remount_CPPFLAGS = $(AM_CPPFLAGS) \ + $(OT_INTERNAL_GIO_UNIX_CFLAGS) -Isrc/switchroot \ + -I$(srcdir)/libglnx $(am__append_71) +ostree_remount_LDADD = $(AM_LDFLAGS) $(OT_INTERNAL_GIO_UNIX_LIBS) libglnx.la +@BUILDOPT_SYSTEMD_TRUE@ostree_prepare_root_LDADD = $(AM_LDFLAGS) $(LIBSYSTEMD_LIBS) +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_SOURCES = src/switchroot/ostree-mount-util.h \ +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ src/switchroot/ostree-system-generator.c + +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libostree +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_LDADD = $(AM_LDFLAGS) libglnx.la libostree-1.la $(OT_INTERNAL_GIO_UNIX_LIBS) +@BUILDOPT_FUSE_TRUE@rofiles_fuse_SOURCES = src/rofiles-fuse/main.c +@BUILDOPT_FUSE_TRUE@rofiles_fuse_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 $(BUILDOPT_FUSE_CFLAGS) \ +@BUILDOPT_FUSE_TRUE@ $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I $(srcdir)/src/libostree -I $(builddir)/src/libostree \ +@BUILDOPT_FUSE_TRUE@ -I$(srcdir)/libglnx + +@BUILDOPT_FUSE_TRUE@rofiles_fuse_LDADD = libglnx.la $(BUILDOPT_FUSE_LIBS) $(OT_INTERNAL_GIO_UNIX_LIBS) libostree-1.la +uninstalled_test_data = tests/ostree-symlink-stamp \ + tests/ostree-prepare-root-symlink-stamp \ + tests/ostree-remount-symlink-stamp $(am__append_80) +dist_uninstalled_test_scripts = tests/test-symbols.sh tests/coccinelle.sh + +# This logic implements ENABLE_INSTALLED_TESTS_EXCLUSIVE; see below. +# The goal here if installed tests are enabled, we explicitly make the +# tests *only* run installed, to avoid having to run them twice in CI. +# This overrides the glib-tap.mk emphasis on doing both, if we'd +# used e.g. `dist_test_scripts`. +dist_test_scripts = $(NULL) $(am__append_91) +test_programs = tests/test-bloom tests/test-repo-finder-config \ + tests/test-repo-finder-mount $(NULL) $(am__append_88) \ + $(am__append_92) +_installed_or_uninstalled_test_scripts = tests/test-basic.sh \ + tests/test-basic-user.sh tests/test-basic-user-only.sh \ + tests/test-basic-root.sh tests/test-pull-subpath.sh \ + tests/test-archivez.sh tests/test-remote-add.sh \ + tests/test-remote-headers.sh tests/test-commit-sign.sh \ + tests/test-export.sh tests/test-help.sh \ + tests/test-libarchive.sh tests/test-parent.sh \ + tests/test-pull-bare.sh tests/test-pull-bareuser.sh \ + tests/test-pull-bareuseronly.sh \ + tests/test-pull2-bareuseronly.sh \ + tests/test-pull-commit-only.sh tests/test-pull-depth.sh \ + tests/test-pull-mirror-summary.sh \ + tests/test-pull-large-metadata.sh tests/test-pull-metalink.sh \ + tests/test-pull-summary-sigs.sh tests/test-pull-resume.sh \ + tests/test-pull-basicauth.sh tests/test-pull-repeated.sh \ + tests/test-pull-sizes.sh tests/test-pull-untrusted.sh \ + tests/test-pull-override-url.sh tests/test-pull-localcache.sh \ + tests/test-local-pull.sh tests/test-local-pull-depth.sh \ + tests/test-admin-upgrade-unconfigured.sh \ + tests/test-admin-upgrade-endoflife.sh \ + tests/test-admin-upgrade-systemd-update.sh \ + tests/test-admin-deploy-syslinux.sh \ + tests/test-admin-deploy-2.sh tests/test-admin-deploy-karg.sh \ + tests/test-admin-deploy-switch.sh \ + tests/test-admin-deploy-etcmerge-cornercases.sh \ + tests/test-admin-deploy-uboot.sh \ + tests/test-admin-deploy-grub2.sh \ + tests/test-admin-deploy-nomerge.sh \ + tests/test-admin-deploy-none.sh \ + tests/test-admin-deploy-bootid-gc.sh \ + tests/test-admin-instutil-set-kargs.sh \ + tests/test-admin-upgrade-not-backwards.sh \ + tests/test-admin-pull-deploy-commit.sh \ + tests/test-admin-pull-deploy-split.sh \ + tests/test-admin-locking.sh tests/test-admin-deploy-clean.sh \ + tests/test-reset-nonlinear.sh tests/test-oldstyle-partial.sh \ + tests/test-delta.sh tests/test-xattrs.sh \ + tests/test-auto-summary.sh tests/test-prune.sh \ + tests/test-concurrency.py tests/test-refs.sh \ + tests/test-demo-buildsystem.sh tests/test-switchroot.sh \ + tests/test-pull-contenturl.sh tests/test-pull-mirrorlist.sh \ + tests/test-summary-update.sh tests/test-summary-view.sh \ + tests/test-no-initramfs.sh tests/test-create-usb.sh \ + tests/test-find-remotes.sh tests/test-fsck-collections.sh \ + tests/test-fsck-delete.sh tests/test-init-collections.sh \ + tests/test-prune-collections.sh tests/test-refs-collections.sh \ + tests/test-remote-add-collections.sh \ + tests/test-repo-finder-mount-integration.sh \ + tests/test-summary-collections.sh \ + tests/test-pull-collections.sh tests/test-config.sh \ + tests/test-signed-commit.sh tests/test-signed-pull.sh \ + tests/test-pre-signed-pull.sh \ + tests/test-signed-pull-summary.sh $(NULL) $(am__append_76) \ + $(am__append_77) $(am__append_79) $(am__append_82) \ + $(am__append_83) +experimental_test_scripts = \ + $(NULL) + +test_extra_programs = \ + tests/get-byte-order \ + tests/repo-finder-mount \ + $(NULL) + +tests_get_byte_order_SOURCES = tests/get-byte-order.c +tests_get_byte_order_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS) +tests_get_byte_order_LDADD = $(GLIB_LIBS) +tests_repo_finder_mount_SOURCES = tests/repo-finder-mount.c +tests_repo_finder_mount_CFLAGS = $(common_tests_cflags) +tests_repo_finder_mount_LDADD = $(common_tests_ldadd) libostreetest.la + +# These call into gjs scripts +js_tests = tests/test-corruption.sh tests/test-pull-corruption.sh +dist_installed_test_data = tests/archive-test.sh \ + tests/pull-test.sh \ + tests/pull-test2.sh \ + tests/admin-test.sh \ + tests/basic-test.sh \ + tests/pre-endian-deltas-repo-big.tar.xz \ + tests/pre-endian-deltas-repo-little.tar.xz \ + tests/fah-deltadata-old.tar.xz \ + tests/fah-deltadata-new.tar.xz \ + tests/ostree-path-traverse.tar.gz \ + tests/pre-signed-pull-data.tar.gz \ + tests/libtest-core.sh \ + $(NULL) + +dist_test_extra_scripts = \ + tests/bootloader-entries-crosscheck.py \ + tests/corrupt-repo-ref.js \ + tests/ostree-grub-generator \ + $(NULL) + + +# We can't use nobase_ as we need to strip off the tests/, can't +# use plain installed_ as we do need the gpghome/ prefix. +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@gpginsttestdir = $(installed_testdir)/gpghome +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@dist_gpginsttest_DATA = tests/gpghome/secring.gpg \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ tests/gpghome/pubring.gpg \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ tests/gpghome/trustdb.gpg \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ tests/gpghome/key1.asc \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ tests/gpghome/key2.asc \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ tests/gpghome/key3.asc + +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@gpginsttest_trusteddir = $(installed_testdir)/gpghome/trusted +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@dist_gpginsttest_trusted_DATA = tests/gpghome/trusted/pubring.gpg +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@gpginsttest_revocdir = $(installed_testdir)/gpghome/revocations +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@dist_gpginsttest_revoc_DATA = \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ tests/gpghome/revocations/key1.rev \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ tests/gpghome/revocations/key2.rev \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ tests/gpghome/revocations/key3.rev \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ $(NULL) + +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@gpgvinsttestdir = $(installed_testdir)/gpg-verify-data +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@dist_gpgvinsttest_DATA = $(addprefix tests/gpg-verify-data/, \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ gpg.conf lgpl2 lgpl2.sig lgpl2.sig0 lgpl2.sig1 lgpl2.sig2 lgpl2.sig3 \ +@ENABLE_INSTALLED_TESTS_TRUE@@USE_GPGME_TRUE@ lgpl2.sig4 pubring.gpg secring.gpg trustdb.gpg) + +js_installed_tests = \ + tests/test-core.js \ + tests/test-remotes-config-dir.js \ + tests/test-sizes.js \ + tests/test-sysroot.js \ + $(NULL) + +test_ltlibraries = libreaddir-rand.la +libreaddir_rand_la_SOURCES = tests/readdir-rand.c +libreaddir_rand_la_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) +libreaddir_rand_la_LIBADD = \ + -ldl \ + $(OT_INTERNAL_GIO_UNIX_LIBS) \ + $(NULL) + +libreaddir_rand_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version \ + $(am__append_86) +_installed_or_uninstalled_test_programs = tests/test-varint \ + tests/test-ot-unix-utils tests/test-bsdiff \ + tests/test-mutable-tree tests/test-keyfile-utils \ + tests/test-ot-opt-utils tests/test-ot-tool-util \ + tests/test-checksum tests/test-lzma tests/test-rollsum \ + tests/test-basic-c tests/test-sysroot-c tests/test-pull-c \ + tests/test-repo tests/test-include-ostree-h tests/test-kargs \ + $(am__append_87) $(am__append_89) +common_tests_cflags = $(ostree_bin_shared_cflags) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/libglnx +common_tests_ldadd = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_GIO_UNIX_LIBS) +libostreetest_la_SOURCES = tests/libostreetest.c tests/test-mock-gio.c tests/test-mock-gio.h +libostreetest_la_CFLAGS = $(common_tests_cflags) -I $(srcdir)/tests +libostreetest_la_LIBADD = $(common_tests_ldadd) +TESTS_CFLAGS = $(common_tests_cflags) +TESTS_LDADD = $(common_tests_ldadd) libostreetest.la +tests_test_rollsum_cli_SOURCES = src/libostree/ostree-rollsum.c tests/test-rollsum-cli.c +tests_test_rollsum_cli_CFLAGS = $(TESTS_CFLAGS) $(OT_DEP_ZLIB_CFLAGS) +tests_test_rollsum_cli_LDADD = $(bupsplitpath) $(TESTS_LDADD) $(OT_DEP_ZLIB_LIBS) +tests_test_rollsum_SOURCES = src/libostree/ostree-rollsum.c tests/test-rollsum.c +tests_test_rollsum_CFLAGS = $(TESTS_CFLAGS) $(OT_DEP_ZLIB_CFLAGS) +tests_test_rollsum_LDADD = $(bupsplitpath) $(TESTS_LDADD) $(OT_DEP_ZLIB_LIBS) +tests_test_bloom_SOURCES = src/libostree/ostree-bloom.c tests/test-bloom.c +tests_test_bloom_CFLAGS = $(TESTS_CFLAGS) +tests_test_bloom_LDADD = $(TESTS_LDADD) +tests_test_include_ostree_h_SOURCES = tests/test-include-ostree-h.c +# Don't use TESTS_CFLAGS so we test if the public header can be included by external programs +tests_test_include_ostree_h_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/src/libostree -I$(builddir)/src/libostree +# Don't define OSTREE_COMPILATION so that we're compiling as if it's an external program +tests_test_include_ostree_h_CPPFLAGS = $(AM_CPPFLAGS) -UOSTREE_COMPILATION +tests_test_include_ostree_h_LDADD = $(TESTS_LDADD) +@USE_AVAHI_TRUE@tests_test_repo_finder_avahi_SOURCES = src/libostree/ostree-repo-finder-avahi-parser.c tests/test-repo-finder-avahi.c +@USE_AVAHI_TRUE@tests_test_repo_finder_avahi_CFLAGS = $(TESTS_CFLAGS) +@USE_AVAHI_TRUE@tests_test_repo_finder_avahi_LDADD = $(TESTS_LDADD) +tests_test_kargs_SOURCES = src/libostree/ostree-kernel-args.c tests/test-kargs.c +tests_test_kargs_CFLAGS = $(TESTS_CFLAGS) +tests_test_kargs_LDADD = $(TESTS_LDADD) +tests_test_repo_finder_config_SOURCES = tests/test-repo-finder-config.c +tests_test_repo_finder_config_CFLAGS = $(TESTS_CFLAGS) +tests_test_repo_finder_config_LDADD = $(TESTS_LDADD) +tests_test_repo_finder_mount_SOURCES = tests/test-repo-finder-mount.c +tests_test_repo_finder_mount_CFLAGS = $(TESTS_CFLAGS) +tests_test_repo_finder_mount_LDADD = $(TESTS_LDADD) +tests_test_mutable_tree_CFLAGS = $(TESTS_CFLAGS) +tests_test_mutable_tree_LDADD = $(TESTS_LDADD) +tests_test_basic_c_CFLAGS = $(TESTS_CFLAGS) +tests_test_basic_c_LDADD = $(TESTS_LDADD) +tests_test_sysroot_c_CFLAGS = $(TESTS_CFLAGS) +tests_test_sysroot_c_LDADD = $(TESTS_LDADD) +tests_test_pull_c_CFLAGS = $(TESTS_CFLAGS) +tests_test_pull_c_LDADD = $(TESTS_LDADD) +tests_test_repo_CFLAGS = $(TESTS_CFLAGS) +tests_test_repo_LDADD = $(TESTS_LDADD) +tests_test_ot_unix_utils_CFLAGS = $(TESTS_CFLAGS) +tests_test_ot_unix_utils_LDADD = $(TESTS_LDADD) +tests_test_varint_SOURCES = src/libostree/ostree-varint.c tests/test-varint.c +tests_test_varint_CFLAGS = $(TESTS_CFLAGS) +tests_test_varint_LDADD = $(TESTS_LDADD) +tests_test_bsdiff_CFLAGS = $(TESTS_CFLAGS) +tests_test_bsdiff_LDADD = libbsdiff.la $(TESTS_LDADD) +tests_test_checksum_SOURCES = \ + src/libostree/ostree-core.c \ + src/libostree/ostree-varint.c \ + tests/test-checksum.c + +tests_test_checksum_CFLAGS = $(TESTS_CFLAGS) $(libglnx_cflags) +tests_test_checksum_LDADD = $(TESTS_LDADD) +tests_test_libarchive_import_SOURCES = tests/test-libarchive-import.c +tests_test_libarchive_import_CFLAGS = $(TESTS_CFLAGS) $(libglnx_cflags) $(OT_DEP_LIBARCHIVE_CFLAGS) +tests_test_libarchive_import_LDADD = $(TESTS_LDADD) $(OT_DEP_LIBARCHIVE_LIBS) +tests_test_keyfile_utils_CFLAGS = $(TESTS_CFLAGS) +tests_test_keyfile_utils_LDADD = $(TESTS_LDADD) +tests_test_ot_opt_utils_CFLAGS = $(TESTS_CFLAGS) +tests_test_ot_opt_utils_LDADD = $(TESTS_LDADD) +tests_test_ot_tool_util_CFLAGS = $(TESTS_CFLAGS) +tests_test_ot_tool_util_LDADD = $(TESTS_LDADD) +tests_test_lzma_SOURCES = src/libostree/ostree-lzma-common.c src/libostree/ostree-lzma-compressor.c \ + src/libostree/ostree-lzma-decompressor.c tests/test-lzma.c + +tests_test_lzma_CFLAGS = $(TESTS_CFLAGS) $(OT_DEP_LZMA_CFLAGS) +tests_test_lzma_LDADD = $(TESTS_LDADD) $(OT_DEP_LZMA_LIBS) +@USE_GPGME_TRUE@tests_test_gpg_verify_result_SOURCES = \ +@USE_GPGME_TRUE@ src/libostree/ostree-gpg-verify-result-private.h \ +@USE_GPGME_TRUE@ tests/test-gpg-verify-result.c + +@USE_GPGME_TRUE@tests_test_gpg_verify_result_CFLAGS = $(TESTS_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) +@USE_GPGME_TRUE@tests_test_gpg_verify_result_LDADD = $(TESTS_LDADD) $(OT_INTERNAL_GPGME_LIBS) + +# See above comment on binding the tests to be either installed or not. +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@dist_installed_test_scripts = $(_installed_or_uninstalled_test_scripts) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@installed_test_programs = $(_installed_or_uninstalled_test_programs) + +# Not using $(libdir) here is intentional, dracut modules go in prefix/lib +@BUILDOPT_DRACUT_TRUE@dracutmoddir = $(prefix)/lib/dracut/modules.d/98ostree +@BUILDOPT_DRACUT_TRUE@dracutmod_SCRIPTS = src/boot/dracut/module-setup.sh +@BUILDOPT_DRACUT_CONF_TRUE@dracutconfdir = $(sysconfdir)/dracut.conf.d +@BUILDOPT_DRACUT_CONF_TRUE@dracutconf_DATA = src/boot/dracut/ostree.conf +@BUILDOPT_MKINITCPIO_TRUE@mkinitcpioinstalldir = $(prefix)/lib/initcpio/install +@BUILDOPT_MKINITCPIO_TRUE@mkinitcpioinstall_SCRIPTS = src/boot/mkinitcpio/ostree +@BUILDOPT_MKINITCPIO_TRUE@mkinitcpioconfdir = $(sysconfdir) +@BUILDOPT_MKINITCPIO_TRUE@mkinitcpioconf_DATA = src/boot/mkinitcpio/ostree-mkinitcpio.conf +@BUILDOPT_SYSTEMD_TRUE@systemdsystemunit_DATA = src/boot/ostree-prepare-root.service \ +@BUILDOPT_SYSTEMD_TRUE@ src/boot/ostree-remount.service \ +@BUILDOPT_SYSTEMD_TRUE@ src/boot/ostree-finalize-staged.service \ +@BUILDOPT_SYSTEMD_TRUE@ src/boot/ostree-finalize-staged.path \ +@BUILDOPT_SYSTEMD_TRUE@ $(NULL) + +@BUILDOPT_SYSTEMD_TRUE@systemdtmpfilesdir = $(prefix)/lib/tmpfiles.d +@BUILDOPT_SYSTEMD_TRUE@dist_systemdtmpfiles_DATA = src/boot/ostree-tmpfiles.conf +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@grub2configdir = $(sysconfdir)/grub.d +@ENABLE_MAN_TRUE@man1_files = ostree.1 ostree-admin-cleanup.1 \ +@ENABLE_MAN_TRUE@ ostree-admin-config-diff.1 \ +@ENABLE_MAN_TRUE@ ostree-admin-deploy.1 ostree-admin-init-fs.1 \ +@ENABLE_MAN_TRUE@ ostree-admin-instutil.1 \ +@ENABLE_MAN_TRUE@ ostree-admin-os-init.1 ostree-admin-status.1 \ +@ENABLE_MAN_TRUE@ ostree-admin-set-origin.1 \ +@ENABLE_MAN_TRUE@ ostree-admin-switch.1 ostree-admin-undeploy.1 \ +@ENABLE_MAN_TRUE@ ostree-admin-upgrade.1 ostree-admin-unlock.1 \ +@ENABLE_MAN_TRUE@ ostree-admin-pin.1 ostree-admin.1 \ +@ENABLE_MAN_TRUE@ ostree-cat.1 ostree-checkout.1 \ +@ENABLE_MAN_TRUE@ ostree-checksum.1 ostree-commit.1 \ +@ENABLE_MAN_TRUE@ ostree-create-usb.1 ostree-export.1 \ +@ENABLE_MAN_TRUE@ ostree-config.1 ostree-diff.1 \ +@ENABLE_MAN_TRUE@ ostree-find-remotes.1 ostree-fsck.1 \ +@ENABLE_MAN_TRUE@ ostree-init.1 ostree-log.1 ostree-ls.1 \ +@ENABLE_MAN_TRUE@ ostree-prune.1 ostree-pull-local.1 \ +@ENABLE_MAN_TRUE@ ostree-pull.1 ostree-refs.1 ostree-remote.1 \ +@ENABLE_MAN_TRUE@ ostree-reset.1 ostree-rev-parse.1 \ +@ENABLE_MAN_TRUE@ ostree-show.1 ostree-sign.1 ostree-summary.1 \ +@ENABLE_MAN_TRUE@ ostree-static-delta.1 $(am__append_98) \ +@ENABLE_MAN_TRUE@ $(am__append_100) $(am__append_101) +@ENABLE_MAN_TRUE@man5_files = ostree.repo.5 ostree.repo-config.5 +@ENABLE_MAN_TRUE@man1_MANS = $(addprefix man/,$(man1_files)) +@ENABLE_MAN_TRUE@man5_MANS = $(addprefix man/,$(man5_files)) +@ENABLE_MAN_TRUE@XSLT_STYLESHEET = http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl +@ENABLE_MAN_TRUE@XSLTPROC_FLAGS = \ +@ENABLE_MAN_TRUE@ --nonet \ +@ENABLE_MAN_TRUE@ --stringparam man.output.quietly 1 \ +@ENABLE_MAN_TRUE@ --stringparam funcsynopsis.style ansi \ +@ENABLE_MAN_TRUE@ --stringparam man.th.extra1.suppress 1 \ +@ENABLE_MAN_TRUE@ --stringparam man.authors.section.enabled 0 \ +@ENABLE_MAN_TRUE@ --stringparam man.copyright.section.enabled 0 + +@ENABLE_MAN_TRUE@XSLTPROC_MAN = $(XSLTPROC) $(XSLTPROC_FLAGS) +completionsdir = @BASH_COMPLETIONSDIR@ +dist_completions_DATA = bash/ostree +embed_dependency = tar -C $(srcdir) --append --exclude='.git/*' --transform="s,^embedded-dependencies/,ostree-embeddeps-$${GITVERSION}/embedded-dependencies/," --file=$${TARFILE_TMP} +git_version_rpm = $$(cd $(srcdir) && git describe | sed -e 's,-,\.,g' -e 's,^v,,') +all: $(BUILT_SOURCES) config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile-decls.am $(top_srcdir)/buildutil/glib-tap.mk $(srcdir)/libglnx/Makefile-libglnx.am.inc $(srcdir)/bsdiff/Makefile-bsdiff.am.inc $(srcdir)/Makefile-otutil.am $(srcdir)/Makefile-libostree.am $(srcdir)/Makefile-libostree-defines.am $(srcdir)/Makefile-ostree.am $(srcdir)/Makefile-switchroot.am $(srcdir)/src/rofiles-fuse/Makefile-inc.am $(srcdir)/Makefile-tests.am $(srcdir)/Makefile-boot.am $(srcdir)/Makefile-man.am $(srcdir)/Makefile-bash.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ + esac; +$(srcdir)/Makefile-decls.am $(top_srcdir)/buildutil/glib-tap.mk $(srcdir)/libglnx/Makefile-libglnx.am.inc $(srcdir)/bsdiff/Makefile-bsdiff.am.inc $(srcdir)/Makefile-otutil.am $(srcdir)/Makefile-libostree.am $(srcdir)/Makefile-libostree-defines.am $(srcdir)/Makefile-ostree.am $(srcdir)/Makefile-switchroot.am $(srcdir)/src/rofiles-fuse/Makefile-inc.am $(srcdir)/Makefile-tests.am $(srcdir)/Makefile-boot.am $(srcdir)/Makefile-man.am $(srcdir)/Makefile-bash.am $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +src/libostree/ostree-1.pc: $(top_builddir)/config.status $(top_srcdir)/src/libostree/ostree-1.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +src/libostree/ostree-version.h: $(top_builddir)/config.status $(top_srcdir)/src/libostree/ostree-version.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-installed_testPROGRAMS: $(installed_test_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(installed_test_PROGRAMS)'; test -n "$(installed_testdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(installed_testdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(installed_testdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(installed_testdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(installed_testdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-installed_testPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(installed_test_PROGRAMS)'; test -n "$(installed_testdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(installed_testdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(installed_testdir)" && rm -f $$files + +clean-installed_testPROGRAMS: + @list='$(installed_test_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-libexecPROGRAMS: $(libexec_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-libexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libexecdir)" && rm -f $$files + +clean-libexecPROGRAMS: + @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-ostree_bootPROGRAMS: $(ostree_boot_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(ostree_boot_PROGRAMS)'; test -n "$(ostree_bootdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(ostree_bootdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(ostree_bootdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(ostree_bootdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(ostree_bootdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-ostree_bootPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(ostree_boot_PROGRAMS)'; test -n "$(ostree_bootdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(ostree_bootdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(ostree_bootdir)" && rm -f $$files + +clean-ostree_bootPROGRAMS: + @list='$(ostree_boot_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-pkglibexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files + +clean-pkglibexecPROGRAMS: + @list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-systemdsystemgeneratorPROGRAMS: $(systemdsystemgenerator_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(systemdsystemgenerator_PROGRAMS)'; test -n "$(systemdsystemgeneratordir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemgeneratordir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemdsystemgeneratordir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(systemdsystemgeneratordir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(systemdsystemgeneratordir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-systemdsystemgeneratorPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(systemdsystemgenerator_PROGRAMS)'; test -n "$(systemdsystemgeneratordir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(systemdsystemgeneratordir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(systemdsystemgeneratordir)" && rm -f $$files + +clean-systemdsystemgeneratorPROGRAMS: + @list='$(systemdsystemgenerator_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkLTLIBRARIES: + -test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES) + @list='$(check_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-installed_testLTLIBRARIES: $(installed_test_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(installed_test_LTLIBRARIES)'; test -n "$(installed_testdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(installed_testdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(installed_testdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(installed_testdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(installed_testdir)"; \ + } + +uninstall-installed_testLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(installed_test_LTLIBRARIES)'; test -n "$(installed_testdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(installed_testdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(installed_testdir)/$$f"; \ + done + +clean-installed_testLTLIBRARIES: + -test -z "$(installed_test_LTLIBRARIES)" || rm -f $(installed_test_LTLIBRARIES) + @list='$(installed_test_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-privlibLTLIBRARIES: $(privlib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(privlib_LTLIBRARIES)'; test -n "$(privlibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(privlibdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(privlibdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(privlibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(privlibdir)"; \ + } + +uninstall-privlibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(privlib_LTLIBRARIES)'; test -n "$(privlibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(privlibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(privlibdir)/$$f"; \ + done + +clean-privlibLTLIBRARIES: + -test -z "$(privlib_LTLIBRARIES)" || rm -f $(privlib_LTLIBRARIES) + @list='$(privlib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +bsdiff/$(am__dirstamp): + @$(MKDIR_P) bsdiff + @: > bsdiff/$(am__dirstamp) +bsdiff/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) bsdiff/$(DEPDIR) + @: > bsdiff/$(DEPDIR)/$(am__dirstamp) +bsdiff/libbsdiff_la-bsdiff.lo: bsdiff/$(am__dirstamp) \ + bsdiff/$(DEPDIR)/$(am__dirstamp) +bsdiff/libbsdiff_la-bspatch.lo: bsdiff/$(am__dirstamp) \ + bsdiff/$(DEPDIR)/$(am__dirstamp) + +libbsdiff.la: $(libbsdiff_la_OBJECTS) $(libbsdiff_la_DEPENDENCIES) $(EXTRA_libbsdiff_la_DEPENDENCIES) + $(AM_V_CCLD)$(libbsdiff_la_LINK) $(libbsdiff_la_OBJECTS) $(libbsdiff_la_LIBADD) $(LIBS) +src/libostree/$(am__dirstamp): + @$(MKDIR_P) src/libostree + @: > src/libostree/$(am__dirstamp) +src/libostree/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/libostree/$(DEPDIR) + @: > src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/bupsplit.lo: src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) + +libbupsplit.la: $(libbupsplit_la_OBJECTS) $(libbupsplit_la_DEPENDENCIES) $(EXTRA_libbupsplit_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(am_libbupsplit_la_rpath) $(libbupsplit_la_OBJECTS) $(libbupsplit_la_LIBADD) $(LIBS) +libglnx/$(am__dirstamp): + @$(MKDIR_P) libglnx + @: > libglnx/$(am__dirstamp) +libglnx/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) libglnx/$(DEPDIR) + @: > libglnx/$(DEPDIR)/$(am__dirstamp) +libglnx/la-glnx-backports.lo: libglnx/$(am__dirstamp) \ + libglnx/$(DEPDIR)/$(am__dirstamp) +libglnx/la-glnx-local-alloc.lo: libglnx/$(am__dirstamp) \ + libglnx/$(DEPDIR)/$(am__dirstamp) +libglnx/la-glnx-errors.lo: libglnx/$(am__dirstamp) \ + libglnx/$(DEPDIR)/$(am__dirstamp) +libglnx/la-glnx-console.lo: libglnx/$(am__dirstamp) \ + libglnx/$(DEPDIR)/$(am__dirstamp) +libglnx/la-glnx-dirfd.lo: libglnx/$(am__dirstamp) \ + libglnx/$(DEPDIR)/$(am__dirstamp) +libglnx/la-glnx-fdio.lo: libglnx/$(am__dirstamp) \ + libglnx/$(DEPDIR)/$(am__dirstamp) +libglnx/la-glnx-lockfile.lo: libglnx/$(am__dirstamp) \ + libglnx/$(DEPDIR)/$(am__dirstamp) +libglnx/la-glnx-xattrs.lo: libglnx/$(am__dirstamp) \ + libglnx/$(DEPDIR)/$(am__dirstamp) +libglnx/la-glnx-shutil.lo: libglnx/$(am__dirstamp) \ + libglnx/$(DEPDIR)/$(am__dirstamp) + +libglnx.la: $(libglnx_la_OBJECTS) $(libglnx_la_DEPENDENCIES) $(EXTRA_libglnx_la_DEPENDENCIES) + $(AM_V_CCLD)$(libglnx_la_LINK) $(libglnx_la_OBJECTS) $(libglnx_la_LIBADD) $(LIBS) +src/libostree/libostree_1_la-ostree-async-progress.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-cmdprivate.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-core.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-dummy-enumtypes.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-checksum-input-stream.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-chain-input-stream.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-lzma-common.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-lzma-compressor.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-lzma-decompressor.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-rollsum.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-varint.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-linuxfsutil.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-diff.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-mutable-tree.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-ref.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-remote.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-checkout.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-commit.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-pull.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-pull-verify.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-libarchive.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-prune.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-refs.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-traverse.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-file.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-file-enumerator.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sepolicy.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sysroot.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sysroot-cleanup.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sysroot-deploy.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-impl-system-generator.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-bootconfig-parser.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-deployment.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-bootloader.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-bootloader-grub2.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-bootloader-zipl.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-bootloader-syslinux.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-bootloader-uboot.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-static-delta-core.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-static-delta-processing.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-static-delta-compilation.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-static-delta-compilation-analysis.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-bloom.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-finder.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-finder-avahi.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-finder-config.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-finder-mount.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-finder-override.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-kernel-args.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-libarchive-input-stream.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-tls-cert-interaction.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-gpg-verifier.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-gpg-verify-result.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-gpg-verify-result-dummy.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-fetcher-util.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-fetcher-uri.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-metalink.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-fetcher-curl.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-soup-uri.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-soup-form.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-fetcher-soup.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sign.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sign-dummy.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-sign-ed25519.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-enumtypes.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) + +libostree-1.la: $(libostree_1_la_OBJECTS) $(libostree_1_la_DEPENDENCIES) $(EXTRA_libostree_1_la_DEPENDENCIES) + $(AM_V_CCLD)$(libostree_1_la_LINK) -rpath $(libdir) $(libostree_1_la_OBJECTS) $(libostree_1_la_LIBADD) $(LIBS) +tests/$(am__dirstamp): + @$(MKDIR_P) tests + @: > tests/$(am__dirstamp) +tests/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) tests/$(DEPDIR) + @: > tests/$(DEPDIR)/$(am__dirstamp) +tests/libostreetest_la-libostreetest.lo: tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) +tests/libostreetest_la-test-mock-gio.lo: tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +libostreetest.la: $(libostreetest_la_OBJECTS) $(libostreetest_la_DEPENDENCIES) $(EXTRA_libostreetest_la_DEPENDENCIES) + $(AM_V_CCLD)$(libostreetest_la_LINK) $(libostreetest_la_OBJECTS) $(libostreetest_la_LIBADD) $(LIBS) +src/libotutil/$(am__dirstamp): + @$(MKDIR_P) src/libotutil + @: > src/libotutil/$(am__dirstamp) +src/libotutil/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/libotutil/$(DEPDIR) + @: > src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-checksum-utils.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-checksum-instream.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-fs-utils.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-keyfile-utils.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-opt-utils.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-unix-utils.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-variant-utils.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-variant-builder.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-gio-utils.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-tool-util.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) +src/libotutil/libotutil_la-ot-gpg-utils.lo: \ + src/libotutil/$(am__dirstamp) \ + src/libotutil/$(DEPDIR)/$(am__dirstamp) + +libotutil.la: $(libotutil_la_OBJECTS) $(libotutil_la_DEPENDENCIES) $(EXTRA_libotutil_la_DEPENDENCIES) + $(AM_V_CCLD)$(libotutil_la_LINK) $(libotutil_la_OBJECTS) $(libotutil_la_LIBADD) $(LIBS) +tests/libreaddir_rand_la-readdir-rand.lo: tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +libreaddir-rand.la: $(libreaddir_rand_la_OBJECTS) $(libreaddir_rand_la_DEPENDENCIES) $(EXTRA_libreaddir_rand_la_DEPENDENCIES) + $(AM_V_CCLD)$(libreaddir_rand_la_LINK) $(am_libreaddir_rand_la_rpath) $(libreaddir_rand_la_OBJECTS) $(libreaddir_rand_la_LIBADD) $(LIBS) +src/ostree/$(am__dirstamp): + @$(MKDIR_P) src/ostree + @: > src/ostree/$(am__dirstamp) +src/ostree/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/ostree/$(DEPDIR) + @: > src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-main.$(OBJEXT): src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-admin.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-cat.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-config.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-checkout.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-checksum.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-commit.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-create-usb.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-diff.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-export.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-find-remotes.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-fsck.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-init.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-pull-local.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-log.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-ls.$(OBJEXT): src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-prune.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-refs.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-remote.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-reset.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-rev-parse.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-sign.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-summary.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-show.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-static-delta.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-main.$(OBJEXT): src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-dump.$(OBJEXT): src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-editor.$(OBJEXT): src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-gpg-sign.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-init-fs.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-diff.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-deploy.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-finalize-staged.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-undeploy.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-instutil.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-cleanup.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-os-init.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-set-origin.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-status.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-switch.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-pin.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-upgrade.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-builtin-unlock.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-admin-functions.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-add.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-delete.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-list.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-show-url.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-refs.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-summary.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-gpg-import.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-add-cookie.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-delete-cookie.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-builtin-list-cookies.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-remote-cookie-util.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-pull.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-ot-builtin-trivial-httpd.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) +src/ostree/ostree-parse-datetime.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) + +ostree$(EXEEXT): $(ostree_OBJECTS) $(ostree_DEPENDENCIES) $(EXTRA_ostree_DEPENDENCIES) + @rm -f ostree$(EXEEXT) + $(AM_V_CCLD)$(ostree_LINK) $(ostree_OBJECTS) $(ostree_LDADD) $(LIBS) +src/switchroot/$(am__dirstamp): + @$(MKDIR_P) src/switchroot + @: > src/switchroot/$(am__dirstamp) +src/switchroot/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/switchroot/$(DEPDIR) + @: > src/switchroot/$(DEPDIR)/$(am__dirstamp) +src/switchroot/ostree_prepare_root-ostree-prepare-root.$(OBJEXT): \ + src/switchroot/$(am__dirstamp) \ + src/switchroot/$(DEPDIR)/$(am__dirstamp) + +@BUILDOPT_USE_STATIC_COMPILER_FALSE@ostree-prepare-root$(EXEEXT): $(ostree_prepare_root_OBJECTS) $(ostree_prepare_root_DEPENDENCIES) $(EXTRA_ostree_prepare_root_DEPENDENCIES) +@BUILDOPT_USE_STATIC_COMPILER_FALSE@ @rm -f ostree-prepare-root$(EXEEXT) +@BUILDOPT_USE_STATIC_COMPILER_FALSE@ $(AM_V_CCLD)$(ostree_prepare_root_LINK) $(ostree_prepare_root_OBJECTS) $(ostree_prepare_root_LDADD) $(LIBS) +src/switchroot/ostree_remount-ostree-remount.$(OBJEXT): \ + src/switchroot/$(am__dirstamp) \ + src/switchroot/$(DEPDIR)/$(am__dirstamp) + +ostree-remount$(EXEEXT): $(ostree_remount_OBJECTS) $(ostree_remount_DEPENDENCIES) $(EXTRA_ostree_remount_DEPENDENCIES) + @rm -f ostree-remount$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(ostree_remount_OBJECTS) $(ostree_remount_LDADD) $(LIBS) +src/switchroot/ostree_system_generator-ostree-system-generator.$(OBJEXT): \ + src/switchroot/$(am__dirstamp) \ + src/switchroot/$(DEPDIR)/$(am__dirstamp) + +ostree-system-generator$(EXEEXT): $(ostree_system_generator_OBJECTS) $(ostree_system_generator_DEPENDENCIES) $(EXTRA_ostree_system_generator_DEPENDENCIES) + @rm -f ostree-system-generator$(EXEEXT) + $(AM_V_CCLD)$(ostree_system_generator_LINK) $(ostree_system_generator_OBJECTS) $(ostree_system_generator_LDADD) $(LIBS) +src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.$(OBJEXT): \ + src/ostree/$(am__dirstamp) \ + src/ostree/$(DEPDIR)/$(am__dirstamp) + +ostree-trivial-httpd$(EXEEXT): $(ostree_trivial_httpd_OBJECTS) $(ostree_trivial_httpd_DEPENDENCIES) $(EXTRA_ostree_trivial_httpd_DEPENDENCIES) + @rm -f ostree-trivial-httpd$(EXEEXT) + $(AM_V_CCLD)$(ostree_trivial_httpd_LINK) $(ostree_trivial_httpd_OBJECTS) $(ostree_trivial_httpd_LDADD) $(LIBS) +src/rofiles-fuse/$(am__dirstamp): + @$(MKDIR_P) src/rofiles-fuse + @: > src/rofiles-fuse/$(am__dirstamp) +src/rofiles-fuse/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/rofiles-fuse/$(DEPDIR) + @: > src/rofiles-fuse/$(DEPDIR)/$(am__dirstamp) +src/rofiles-fuse/rofiles_fuse-main.$(OBJEXT): \ + src/rofiles-fuse/$(am__dirstamp) \ + src/rofiles-fuse/$(DEPDIR)/$(am__dirstamp) + +rofiles-fuse$(EXEEXT): $(rofiles_fuse_OBJECTS) $(rofiles_fuse_DEPENDENCIES) $(EXTRA_rofiles_fuse_DEPENDENCIES) + @rm -f rofiles-fuse$(EXEEXT) + $(AM_V_CCLD)$(rofiles_fuse_LINK) $(rofiles_fuse_OBJECTS) $(rofiles_fuse_LDADD) $(LIBS) +libglnx/tests/$(am__dirstamp): + @$(MKDIR_P) libglnx/tests + @: > libglnx/tests/$(am__dirstamp) +libglnx/tests/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) libglnx/tests/$(DEPDIR) + @: > libglnx/tests/$(DEPDIR)/$(am__dirstamp) +libglnx/tests/test_libglnx_errors-libglnx-testlib.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) +libglnx/tests/test_libglnx_errors-test-libglnx-errors.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) + +test-libglnx-errors$(EXEEXT): $(test_libglnx_errors_OBJECTS) $(test_libglnx_errors_DEPENDENCIES) $(EXTRA_test_libglnx_errors_DEPENDENCIES) + @rm -f test-libglnx-errors$(EXEEXT) + $(AM_V_CCLD)$(test_libglnx_errors_LINK) $(test_libglnx_errors_OBJECTS) $(test_libglnx_errors_LDADD) $(LIBS) +libglnx/tests/test_libglnx_fdio-libglnx-testlib.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) +libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) + +test-libglnx-fdio$(EXEEXT): $(test_libglnx_fdio_OBJECTS) $(test_libglnx_fdio_DEPENDENCIES) $(EXTRA_test_libglnx_fdio_DEPENDENCIES) + @rm -f test-libglnx-fdio$(EXEEXT) + $(AM_V_CCLD)$(test_libglnx_fdio_LINK) $(test_libglnx_fdio_OBJECTS) $(test_libglnx_fdio_LDADD) $(LIBS) +libglnx/tests/test_libglnx_macros-libglnx-testlib.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) +libglnx/tests/test_libglnx_macros-test-libglnx-macros.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) + +test-libglnx-macros$(EXEEXT): $(test_libglnx_macros_OBJECTS) $(test_libglnx_macros_DEPENDENCIES) $(EXTRA_test_libglnx_macros_DEPENDENCIES) + @rm -f test-libglnx-macros$(EXEEXT) + $(AM_V_CCLD)$(test_libglnx_macros_LINK) $(test_libglnx_macros_OBJECTS) $(test_libglnx_macros_LDADD) $(LIBS) +libglnx/tests/test_libglnx_shutil-libglnx-testlib.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) +libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) + +test-libglnx-shutil$(EXEEXT): $(test_libglnx_shutil_OBJECTS) $(test_libglnx_shutil_DEPENDENCIES) $(EXTRA_test_libglnx_shutil_DEPENDENCIES) + @rm -f test-libglnx-shutil$(EXEEXT) + $(AM_V_CCLD)$(test_libglnx_shutil_LINK) $(test_libglnx_shutil_OBJECTS) $(test_libglnx_shutil_LDADD) $(LIBS) +libglnx/tests/test_libglnx_xattrs-libglnx-testlib.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) +libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.$(OBJEXT): \ + libglnx/tests/$(am__dirstamp) \ + libglnx/tests/$(DEPDIR)/$(am__dirstamp) + +test-libglnx-xattrs$(EXEEXT): $(test_libglnx_xattrs_OBJECTS) $(test_libglnx_xattrs_DEPENDENCIES) $(EXTRA_test_libglnx_xattrs_DEPENDENCIES) + @rm -f test-libglnx-xattrs$(EXEEXT) + $(AM_V_CCLD)$(test_libglnx_xattrs_LINK) $(test_libglnx_xattrs_OBJECTS) $(test_libglnx_xattrs_LDADD) $(LIBS) +tests/get_byte_order-get-byte-order.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/get-byte-order$(EXEEXT): $(tests_get_byte_order_OBJECTS) $(tests_get_byte_order_DEPENDENCIES) $(EXTRA_tests_get_byte_order_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/get-byte-order$(EXEEXT) + $(AM_V_CCLD)$(tests_get_byte_order_LINK) $(tests_get_byte_order_OBJECTS) $(tests_get_byte_order_LDADD) $(LIBS) +tests/repo_finder_mount-repo-finder-mount.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/repo-finder-mount$(EXEEXT): $(tests_repo_finder_mount_OBJECTS) $(tests_repo_finder_mount_DEPENDENCIES) $(EXTRA_tests_repo_finder_mount_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/repo-finder-mount$(EXEEXT) + $(AM_V_CCLD)$(tests_repo_finder_mount_LINK) $(tests_repo_finder_mount_OBJECTS) $(tests_repo_finder_mount_LDADD) $(LIBS) +tests/test_basic_c-test-basic-c.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-basic-c$(EXEEXT): $(tests_test_basic_c_OBJECTS) $(tests_test_basic_c_DEPENDENCIES) $(EXTRA_tests_test_basic_c_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-basic-c$(EXEEXT) + $(AM_V_CCLD)$(tests_test_basic_c_LINK) $(tests_test_basic_c_OBJECTS) $(tests_test_basic_c_LDADD) $(LIBS) +src/libostree/tests_test_bloom-ostree-bloom.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +tests/test_bloom-test-bloom.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-bloom$(EXEEXT): $(tests_test_bloom_OBJECTS) $(tests_test_bloom_DEPENDENCIES) $(EXTRA_tests_test_bloom_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-bloom$(EXEEXT) + $(AM_V_CCLD)$(tests_test_bloom_LINK) $(tests_test_bloom_OBJECTS) $(tests_test_bloom_LDADD) $(LIBS) +tests/test_bsdiff-test-bsdiff.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-bsdiff$(EXEEXT): $(tests_test_bsdiff_OBJECTS) $(tests_test_bsdiff_DEPENDENCIES) $(EXTRA_tests_test_bsdiff_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-bsdiff$(EXEEXT) + $(AM_V_CCLD)$(tests_test_bsdiff_LINK) $(tests_test_bsdiff_OBJECTS) $(tests_test_bsdiff_LDADD) $(LIBS) +src/libostree/tests_test_checksum-ostree-core.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/tests_test_checksum-ostree-varint.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +tests/test_checksum-test-checksum.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-checksum$(EXEEXT): $(tests_test_checksum_OBJECTS) $(tests_test_checksum_DEPENDENCIES) $(EXTRA_tests_test_checksum_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-checksum$(EXEEXT) + $(AM_V_CCLD)$(tests_test_checksum_LINK) $(tests_test_checksum_OBJECTS) $(tests_test_checksum_LDADD) $(LIBS) +tests/test_gpg_verify_result-test-gpg-verify-result.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-gpg-verify-result$(EXEEXT): $(tests_test_gpg_verify_result_OBJECTS) $(tests_test_gpg_verify_result_DEPENDENCIES) $(EXTRA_tests_test_gpg_verify_result_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-gpg-verify-result$(EXEEXT) + $(AM_V_CCLD)$(tests_test_gpg_verify_result_LINK) $(tests_test_gpg_verify_result_OBJECTS) $(tests_test_gpg_verify_result_LDADD) $(LIBS) +tests/test_include_ostree_h-test-include-ostree-h.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-include-ostree-h$(EXEEXT): $(tests_test_include_ostree_h_OBJECTS) $(tests_test_include_ostree_h_DEPENDENCIES) $(EXTRA_tests_test_include_ostree_h_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-include-ostree-h$(EXEEXT) + $(AM_V_CCLD)$(tests_test_include_ostree_h_LINK) $(tests_test_include_ostree_h_OBJECTS) $(tests_test_include_ostree_h_LDADD) $(LIBS) +src/libostree/tests_test_kargs-ostree-kernel-args.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +tests/test_kargs-test-kargs.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-kargs$(EXEEXT): $(tests_test_kargs_OBJECTS) $(tests_test_kargs_DEPENDENCIES) $(EXTRA_tests_test_kargs_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-kargs$(EXEEXT) + $(AM_V_CCLD)$(tests_test_kargs_LINK) $(tests_test_kargs_OBJECTS) $(tests_test_kargs_LDADD) $(LIBS) +tests/test_keyfile_utils-test-keyfile-utils.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-keyfile-utils$(EXEEXT): $(tests_test_keyfile_utils_OBJECTS) $(tests_test_keyfile_utils_DEPENDENCIES) $(EXTRA_tests_test_keyfile_utils_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-keyfile-utils$(EXEEXT) + $(AM_V_CCLD)$(tests_test_keyfile_utils_LINK) $(tests_test_keyfile_utils_OBJECTS) $(tests_test_keyfile_utils_LDADD) $(LIBS) +tests/test_libarchive_import-test-libarchive-import.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-libarchive-import$(EXEEXT): $(tests_test_libarchive_import_OBJECTS) $(tests_test_libarchive_import_DEPENDENCIES) $(EXTRA_tests_test_libarchive_import_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-libarchive-import$(EXEEXT) + $(AM_V_CCLD)$(tests_test_libarchive_import_LINK) $(tests_test_libarchive_import_OBJECTS) $(tests_test_libarchive_import_LDADD) $(LIBS) +src/libostree/tests_test_lzma-ostree-lzma-common.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/tests_test_lzma-ostree-lzma-compressor.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/tests_test_lzma-ostree-lzma-decompressor.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +tests/test_lzma-test-lzma.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-lzma$(EXEEXT): $(tests_test_lzma_OBJECTS) $(tests_test_lzma_DEPENDENCIES) $(EXTRA_tests_test_lzma_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-lzma$(EXEEXT) + $(AM_V_CCLD)$(tests_test_lzma_LINK) $(tests_test_lzma_OBJECTS) $(tests_test_lzma_LDADD) $(LIBS) +tests/test_mutable_tree-test-mutable-tree.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-mutable-tree$(EXEEXT): $(tests_test_mutable_tree_OBJECTS) $(tests_test_mutable_tree_DEPENDENCIES) $(EXTRA_tests_test_mutable_tree_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-mutable-tree$(EXEEXT) + $(AM_V_CCLD)$(tests_test_mutable_tree_LINK) $(tests_test_mutable_tree_OBJECTS) $(tests_test_mutable_tree_LDADD) $(LIBS) +tests/test_ot_opt_utils-test-ot-opt-utils.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-ot-opt-utils$(EXEEXT): $(tests_test_ot_opt_utils_OBJECTS) $(tests_test_ot_opt_utils_DEPENDENCIES) $(EXTRA_tests_test_ot_opt_utils_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-ot-opt-utils$(EXEEXT) + $(AM_V_CCLD)$(tests_test_ot_opt_utils_LINK) $(tests_test_ot_opt_utils_OBJECTS) $(tests_test_ot_opt_utils_LDADD) $(LIBS) +tests/test_ot_tool_util-test-ot-tool-util.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-ot-tool-util$(EXEEXT): $(tests_test_ot_tool_util_OBJECTS) $(tests_test_ot_tool_util_DEPENDENCIES) $(EXTRA_tests_test_ot_tool_util_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-ot-tool-util$(EXEEXT) + $(AM_V_CCLD)$(tests_test_ot_tool_util_LINK) $(tests_test_ot_tool_util_OBJECTS) $(tests_test_ot_tool_util_LDADD) $(LIBS) +tests/test_ot_unix_utils-test-ot-unix-utils.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-ot-unix-utils$(EXEEXT): $(tests_test_ot_unix_utils_OBJECTS) $(tests_test_ot_unix_utils_DEPENDENCIES) $(EXTRA_tests_test_ot_unix_utils_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-ot-unix-utils$(EXEEXT) + $(AM_V_CCLD)$(tests_test_ot_unix_utils_LINK) $(tests_test_ot_unix_utils_OBJECTS) $(tests_test_ot_unix_utils_LDADD) $(LIBS) +tests/test_pull_c-test-pull-c.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-pull-c$(EXEEXT): $(tests_test_pull_c_OBJECTS) $(tests_test_pull_c_DEPENDENCIES) $(EXTRA_tests_test_pull_c_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-pull-c$(EXEEXT) + $(AM_V_CCLD)$(tests_test_pull_c_LINK) $(tests_test_pull_c_OBJECTS) $(tests_test_pull_c_LDADD) $(LIBS) +tests/test_repo-test-repo.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-repo$(EXEEXT): $(tests_test_repo_OBJECTS) $(tests_test_repo_DEPENDENCIES) $(EXTRA_tests_test_repo_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-repo$(EXEEXT) + $(AM_V_CCLD)$(tests_test_repo_LINK) $(tests_test_repo_OBJECTS) $(tests_test_repo_LDADD) $(LIBS) +src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +tests/test_repo_finder_avahi-test-repo-finder-avahi.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-repo-finder-avahi$(EXEEXT): $(tests_test_repo_finder_avahi_OBJECTS) $(tests_test_repo_finder_avahi_DEPENDENCIES) $(EXTRA_tests_test_repo_finder_avahi_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-repo-finder-avahi$(EXEEXT) + $(AM_V_CCLD)$(tests_test_repo_finder_avahi_LINK) $(tests_test_repo_finder_avahi_OBJECTS) $(tests_test_repo_finder_avahi_LDADD) $(LIBS) +tests/test_repo_finder_config-test-repo-finder-config.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-repo-finder-config$(EXEEXT): $(tests_test_repo_finder_config_OBJECTS) $(tests_test_repo_finder_config_DEPENDENCIES) $(EXTRA_tests_test_repo_finder_config_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-repo-finder-config$(EXEEXT) + $(AM_V_CCLD)$(tests_test_repo_finder_config_LINK) $(tests_test_repo_finder_config_OBJECTS) $(tests_test_repo_finder_config_LDADD) $(LIBS) +tests/test_repo_finder_mount-test-repo-finder-mount.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-repo-finder-mount$(EXEEXT): $(tests_test_repo_finder_mount_OBJECTS) $(tests_test_repo_finder_mount_DEPENDENCIES) $(EXTRA_tests_test_repo_finder_mount_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-repo-finder-mount$(EXEEXT) + $(AM_V_CCLD)$(tests_test_repo_finder_mount_LINK) $(tests_test_repo_finder_mount_OBJECTS) $(tests_test_repo_finder_mount_LDADD) $(LIBS) +src/libostree/tests_test_rollsum-ostree-rollsum.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +tests/test_rollsum-test-rollsum.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-rollsum$(EXEEXT): $(tests_test_rollsum_OBJECTS) $(tests_test_rollsum_DEPENDENCIES) $(EXTRA_tests_test_rollsum_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-rollsum$(EXEEXT) + $(AM_V_CCLD)$(tests_test_rollsum_LINK) $(tests_test_rollsum_OBJECTS) $(tests_test_rollsum_LDADD) $(LIBS) +src/libostree/tests_test_rollsum_cli-ostree-rollsum.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +tests/test_rollsum_cli-test-rollsum-cli.$(OBJEXT): \ + tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-rollsum-cli$(EXEEXT): $(tests_test_rollsum_cli_OBJECTS) $(tests_test_rollsum_cli_DEPENDENCIES) $(EXTRA_tests_test_rollsum_cli_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-rollsum-cli$(EXEEXT) + $(AM_V_CCLD)$(tests_test_rollsum_cli_LINK) $(tests_test_rollsum_cli_OBJECTS) $(tests_test_rollsum_cli_LDADD) $(LIBS) +tests/test_sysroot_c-test-sysroot-c.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-sysroot-c$(EXEEXT): $(tests_test_sysroot_c_OBJECTS) $(tests_test_sysroot_c_DEPENDENCIES) $(EXTRA_tests_test_sysroot_c_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-sysroot-c$(EXEEXT) + $(AM_V_CCLD)$(tests_test_sysroot_c_LINK) $(tests_test_sysroot_c_OBJECTS) $(tests_test_sysroot_c_LDADD) $(LIBS) +src/libostree/tests_test_varint-ostree-varint.$(OBJEXT): \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) +tests/test_varint-test-varint.$(OBJEXT): tests/$(am__dirstamp) \ + tests/$(DEPDIR)/$(am__dirstamp) + +tests/test-varint$(EXEEXT): $(tests_test_varint_OBJECTS) $(tests_test_varint_DEPENDENCIES) $(EXTRA_tests_test_varint_DEPENDENCIES) tests/$(am__dirstamp) + @rm -f tests/test-varint$(EXEEXT) + $(AM_V_CCLD)$(tests_test_varint_LINK) $(tests_test_varint_OBJECTS) $(tests_test_varint_LDADD) $(LIBS) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) +install-dracutmodSCRIPTS: $(dracutmod_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(dracutmod_SCRIPTS)'; test -n "$(dracutmoddir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dracutmoddir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dracutmoddir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(dracutmoddir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(dracutmoddir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-dracutmodSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(dracutmod_SCRIPTS)'; test -n "$(dracutmoddir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(dracutmoddir)'; $(am__uninstall_files_from_dir) +install-installed_testSCRIPTS: $(installed_test_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(installed_test_SCRIPTS)'; test -n "$(installed_testdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(installed_testdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(installed_testdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(installed_testdir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(installed_testdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-installed_testSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(installed_test_SCRIPTS)'; test -n "$(installed_testdir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(installed_testdir)'; $(am__uninstall_files_from_dir) +install-mkinitcpioinstallSCRIPTS: $(mkinitcpioinstall_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(mkinitcpioinstall_SCRIPTS)'; test -n "$(mkinitcpioinstalldir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(mkinitcpioinstalldir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(mkinitcpioinstalldir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(mkinitcpioinstalldir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(mkinitcpioinstalldir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-mkinitcpioinstallSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(mkinitcpioinstall_SCRIPTS)'; test -n "$(mkinitcpioinstalldir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(mkinitcpioinstalldir)'; $(am__uninstall_files_from_dir) +install-ostree_bootSCRIPTS: $(ostree_boot_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(ostree_boot_SCRIPTS)'; test -n "$(ostree_bootdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(ostree_bootdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(ostree_bootdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(ostree_bootdir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(ostree_bootdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-ostree_bootSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(ostree_boot_SCRIPTS)'; test -n "$(ostree_bootdir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(ostree_bootdir)'; $(am__uninstall_files_from_dir) +install-pkglibexecSCRIPTS: $(pkglibexec_SCRIPTS) + @$(NORMAL_INSTALL) + @list='$(pkglibexec_SCRIPTS)'; test -n "$(pkglibexecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-pkglibexecSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(pkglibexec_SCRIPTS)'; test -n "$(pkglibexecdir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + dir='$(DESTDIR)$(pkglibexecdir)'; $(am__uninstall_files_from_dir) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f bsdiff/*.$(OBJEXT) + -rm -f bsdiff/*.lo + -rm -f libglnx/*.$(OBJEXT) + -rm -f libglnx/*.lo + -rm -f libglnx/tests/*.$(OBJEXT) + -rm -f src/libostree/*.$(OBJEXT) + -rm -f src/libostree/*.lo + -rm -f src/libotutil/*.$(OBJEXT) + -rm -f src/libotutil/*.lo + -rm -f src/ostree/*.$(OBJEXT) + -rm -f src/rofiles-fuse/*.$(OBJEXT) + -rm -f src/switchroot/*.$(OBJEXT) + -rm -f tests/*.$(OBJEXT) + -rm -f tests/*.lo + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@bsdiff/$(DEPDIR)/libbsdiff_la-bspatch.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/$(DEPDIR)/la-glnx-backports.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/$(DEPDIR)/la-glnx-console.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/$(DEPDIR)/la-glnx-dirfd.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/$(DEPDIR)/la-glnx-errors.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/$(DEPDIR)/la-glnx-fdio.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/$(DEPDIR)/la-glnx-local-alloc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/$(DEPDIR)/la-glnx-lockfile.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/$(DEPDIR)/la-glnx-shutil.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/$(DEPDIR)/la-glnx-xattrs.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/bupsplit.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-async-progress.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-bloom.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-grub2.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-syslinux.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-uboot.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-zipl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-chain-input-stream.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-checksum-input-stream.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-cmdprivate.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-core.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-deployment.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-diff.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-dummy-enumtypes.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-curl.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-soup.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-uri.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verifier.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result-dummy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-kernel-args.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-libarchive-input-stream.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-linuxfsutil.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-common.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-compressor.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-decompressor.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-metalink.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-mutable-tree.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-ref.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-checkout.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-commit.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file-enumerator.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-config.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-mount.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-core.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-processing.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-traverse.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-deploy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-upgrader.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-tls-cert-interaction.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-varint.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-instream.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-fs-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-keyfile-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-dump.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-editor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree-parse-datetime.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/get_byte_order-get-byte-order.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/libostreetest_la-libostreetest.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/libostreetest_la-test-mock-gio.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/libreaddir_rand_la-readdir-rand.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_basic_c-test-basic-c.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_bloom-test-bloom.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_checksum-test-checksum.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_kargs-test-kargs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_lzma-test-lzma.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_pull_c-test-pull-c.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_repo-test-repo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_rollsum-test-rollsum.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/test_varint-test-varint.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +bsdiff/libbsdiff_la-bsdiff.lo: bsdiff/bsdiff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libbsdiff_la_CFLAGS) $(CFLAGS) -MT bsdiff/libbsdiff_la-bsdiff.lo -MD -MP -MF bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Tpo -c -o bsdiff/libbsdiff_la-bsdiff.lo `test -f 'bsdiff/bsdiff.c' || echo '$(srcdir)/'`bsdiff/bsdiff.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Tpo bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bsdiff/bsdiff.c' object='bsdiff/libbsdiff_la-bsdiff.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libbsdiff_la_CFLAGS) $(CFLAGS) -c -o bsdiff/libbsdiff_la-bsdiff.lo `test -f 'bsdiff/bsdiff.c' || echo '$(srcdir)/'`bsdiff/bsdiff.c + +bsdiff/libbsdiff_la-bspatch.lo: bsdiff/bspatch.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libbsdiff_la_CFLAGS) $(CFLAGS) -MT bsdiff/libbsdiff_la-bspatch.lo -MD -MP -MF bsdiff/$(DEPDIR)/libbsdiff_la-bspatch.Tpo -c -o bsdiff/libbsdiff_la-bspatch.lo `test -f 'bsdiff/bspatch.c' || echo '$(srcdir)/'`bsdiff/bspatch.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) bsdiff/$(DEPDIR)/libbsdiff_la-bspatch.Tpo bsdiff/$(DEPDIR)/libbsdiff_la-bspatch.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bsdiff/bspatch.c' object='bsdiff/libbsdiff_la-bspatch.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libbsdiff_la_CFLAGS) $(CFLAGS) -c -o bsdiff/libbsdiff_la-bspatch.lo `test -f 'bsdiff/bspatch.c' || echo '$(srcdir)/'`bsdiff/bspatch.c + +libglnx/la-glnx-backports.lo: libglnx/glnx-backports.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -MT libglnx/la-glnx-backports.lo -MD -MP -MF libglnx/$(DEPDIR)/la-glnx-backports.Tpo -c -o libglnx/la-glnx-backports.lo `test -f 'libglnx/glnx-backports.c' || echo '$(srcdir)/'`libglnx/glnx-backports.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/$(DEPDIR)/la-glnx-backports.Tpo libglnx/$(DEPDIR)/la-glnx-backports.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/glnx-backports.c' object='libglnx/la-glnx-backports.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -c -o libglnx/la-glnx-backports.lo `test -f 'libglnx/glnx-backports.c' || echo '$(srcdir)/'`libglnx/glnx-backports.c + +libglnx/la-glnx-local-alloc.lo: libglnx/glnx-local-alloc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -MT libglnx/la-glnx-local-alloc.lo -MD -MP -MF libglnx/$(DEPDIR)/la-glnx-local-alloc.Tpo -c -o libglnx/la-glnx-local-alloc.lo `test -f 'libglnx/glnx-local-alloc.c' || echo '$(srcdir)/'`libglnx/glnx-local-alloc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/$(DEPDIR)/la-glnx-local-alloc.Tpo libglnx/$(DEPDIR)/la-glnx-local-alloc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/glnx-local-alloc.c' object='libglnx/la-glnx-local-alloc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -c -o libglnx/la-glnx-local-alloc.lo `test -f 'libglnx/glnx-local-alloc.c' || echo '$(srcdir)/'`libglnx/glnx-local-alloc.c + +libglnx/la-glnx-errors.lo: libglnx/glnx-errors.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -MT libglnx/la-glnx-errors.lo -MD -MP -MF libglnx/$(DEPDIR)/la-glnx-errors.Tpo -c -o libglnx/la-glnx-errors.lo `test -f 'libglnx/glnx-errors.c' || echo '$(srcdir)/'`libglnx/glnx-errors.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/$(DEPDIR)/la-glnx-errors.Tpo libglnx/$(DEPDIR)/la-glnx-errors.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/glnx-errors.c' object='libglnx/la-glnx-errors.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -c -o libglnx/la-glnx-errors.lo `test -f 'libglnx/glnx-errors.c' || echo '$(srcdir)/'`libglnx/glnx-errors.c + +libglnx/la-glnx-console.lo: libglnx/glnx-console.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -MT libglnx/la-glnx-console.lo -MD -MP -MF libglnx/$(DEPDIR)/la-glnx-console.Tpo -c -o libglnx/la-glnx-console.lo `test -f 'libglnx/glnx-console.c' || echo '$(srcdir)/'`libglnx/glnx-console.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/$(DEPDIR)/la-glnx-console.Tpo libglnx/$(DEPDIR)/la-glnx-console.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/glnx-console.c' object='libglnx/la-glnx-console.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -c -o libglnx/la-glnx-console.lo `test -f 'libglnx/glnx-console.c' || echo '$(srcdir)/'`libglnx/glnx-console.c + +libglnx/la-glnx-dirfd.lo: libglnx/glnx-dirfd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -MT libglnx/la-glnx-dirfd.lo -MD -MP -MF libglnx/$(DEPDIR)/la-glnx-dirfd.Tpo -c -o libglnx/la-glnx-dirfd.lo `test -f 'libglnx/glnx-dirfd.c' || echo '$(srcdir)/'`libglnx/glnx-dirfd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/$(DEPDIR)/la-glnx-dirfd.Tpo libglnx/$(DEPDIR)/la-glnx-dirfd.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/glnx-dirfd.c' object='libglnx/la-glnx-dirfd.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -c -o libglnx/la-glnx-dirfd.lo `test -f 'libglnx/glnx-dirfd.c' || echo '$(srcdir)/'`libglnx/glnx-dirfd.c + +libglnx/la-glnx-fdio.lo: libglnx/glnx-fdio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -MT libglnx/la-glnx-fdio.lo -MD -MP -MF libglnx/$(DEPDIR)/la-glnx-fdio.Tpo -c -o libglnx/la-glnx-fdio.lo `test -f 'libglnx/glnx-fdio.c' || echo '$(srcdir)/'`libglnx/glnx-fdio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/$(DEPDIR)/la-glnx-fdio.Tpo libglnx/$(DEPDIR)/la-glnx-fdio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/glnx-fdio.c' object='libglnx/la-glnx-fdio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -c -o libglnx/la-glnx-fdio.lo `test -f 'libglnx/glnx-fdio.c' || echo '$(srcdir)/'`libglnx/glnx-fdio.c + +libglnx/la-glnx-lockfile.lo: libglnx/glnx-lockfile.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -MT libglnx/la-glnx-lockfile.lo -MD -MP -MF libglnx/$(DEPDIR)/la-glnx-lockfile.Tpo -c -o libglnx/la-glnx-lockfile.lo `test -f 'libglnx/glnx-lockfile.c' || echo '$(srcdir)/'`libglnx/glnx-lockfile.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/$(DEPDIR)/la-glnx-lockfile.Tpo libglnx/$(DEPDIR)/la-glnx-lockfile.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/glnx-lockfile.c' object='libglnx/la-glnx-lockfile.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -c -o libglnx/la-glnx-lockfile.lo `test -f 'libglnx/glnx-lockfile.c' || echo '$(srcdir)/'`libglnx/glnx-lockfile.c + +libglnx/la-glnx-xattrs.lo: libglnx/glnx-xattrs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -MT libglnx/la-glnx-xattrs.lo -MD -MP -MF libglnx/$(DEPDIR)/la-glnx-xattrs.Tpo -c -o libglnx/la-glnx-xattrs.lo `test -f 'libglnx/glnx-xattrs.c' || echo '$(srcdir)/'`libglnx/glnx-xattrs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/$(DEPDIR)/la-glnx-xattrs.Tpo libglnx/$(DEPDIR)/la-glnx-xattrs.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/glnx-xattrs.c' object='libglnx/la-glnx-xattrs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -c -o libglnx/la-glnx-xattrs.lo `test -f 'libglnx/glnx-xattrs.c' || echo '$(srcdir)/'`libglnx/glnx-xattrs.c + +libglnx/la-glnx-shutil.lo: libglnx/glnx-shutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -MT libglnx/la-glnx-shutil.lo -MD -MP -MF libglnx/$(DEPDIR)/la-glnx-shutil.Tpo -c -o libglnx/la-glnx-shutil.lo `test -f 'libglnx/glnx-shutil.c' || echo '$(srcdir)/'`libglnx/glnx-shutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/$(DEPDIR)/la-glnx-shutil.Tpo libglnx/$(DEPDIR)/la-glnx-shutil.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/glnx-shutil.c' object='libglnx/la-glnx-shutil.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libglnx_la_CFLAGS) $(CFLAGS) -c -o libglnx/la-glnx-shutil.lo `test -f 'libglnx/glnx-shutil.c' || echo '$(srcdir)/'`libglnx/glnx-shutil.c + +src/libostree/libostree_1_la-ostree-async-progress.lo: src/libostree/ostree-async-progress.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-async-progress.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-async-progress.Tpo -c -o src/libostree/libostree_1_la-ostree-async-progress.lo `test -f 'src/libostree/ostree-async-progress.c' || echo '$(srcdir)/'`src/libostree/ostree-async-progress.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-async-progress.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-async-progress.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-async-progress.c' object='src/libostree/libostree_1_la-ostree-async-progress.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-async-progress.lo `test -f 'src/libostree/ostree-async-progress.c' || echo '$(srcdir)/'`src/libostree/ostree-async-progress.c + +src/libostree/libostree_1_la-ostree-cmdprivate.lo: src/libostree/ostree-cmdprivate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-cmdprivate.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-cmdprivate.Tpo -c -o src/libostree/libostree_1_la-ostree-cmdprivate.lo `test -f 'src/libostree/ostree-cmdprivate.c' || echo '$(srcdir)/'`src/libostree/ostree-cmdprivate.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-cmdprivate.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-cmdprivate.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-cmdprivate.c' object='src/libostree/libostree_1_la-ostree-cmdprivate.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-cmdprivate.lo `test -f 'src/libostree/ostree-cmdprivate.c' || echo '$(srcdir)/'`src/libostree/ostree-cmdprivate.c + +src/libostree/libostree_1_la-ostree-core.lo: src/libostree/ostree-core.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-core.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-core.Tpo -c -o src/libostree/libostree_1_la-ostree-core.lo `test -f 'src/libostree/ostree-core.c' || echo '$(srcdir)/'`src/libostree/ostree-core.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-core.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-core.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-core.c' object='src/libostree/libostree_1_la-ostree-core.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-core.lo `test -f 'src/libostree/ostree-core.c' || echo '$(srcdir)/'`src/libostree/ostree-core.c + +src/libostree/libostree_1_la-ostree-dummy-enumtypes.lo: src/libostree/ostree-dummy-enumtypes.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-dummy-enumtypes.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-dummy-enumtypes.Tpo -c -o src/libostree/libostree_1_la-ostree-dummy-enumtypes.lo `test -f 'src/libostree/ostree-dummy-enumtypes.c' || echo '$(srcdir)/'`src/libostree/ostree-dummy-enumtypes.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-dummy-enumtypes.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-dummy-enumtypes.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-dummy-enumtypes.c' object='src/libostree/libostree_1_la-ostree-dummy-enumtypes.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-dummy-enumtypes.lo `test -f 'src/libostree/ostree-dummy-enumtypes.c' || echo '$(srcdir)/'`src/libostree/ostree-dummy-enumtypes.c + +src/libostree/libostree_1_la-ostree-checksum-input-stream.lo: src/libostree/ostree-checksum-input-stream.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-checksum-input-stream.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-checksum-input-stream.Tpo -c -o src/libostree/libostree_1_la-ostree-checksum-input-stream.lo `test -f 'src/libostree/ostree-checksum-input-stream.c' || echo '$(srcdir)/'`src/libostree/ostree-checksum-input-stream.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-checksum-input-stream.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-checksum-input-stream.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-checksum-input-stream.c' object='src/libostree/libostree_1_la-ostree-checksum-input-stream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-checksum-input-stream.lo `test -f 'src/libostree/ostree-checksum-input-stream.c' || echo '$(srcdir)/'`src/libostree/ostree-checksum-input-stream.c + +src/libostree/libostree_1_la-ostree-chain-input-stream.lo: src/libostree/ostree-chain-input-stream.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-chain-input-stream.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-chain-input-stream.Tpo -c -o src/libostree/libostree_1_la-ostree-chain-input-stream.lo `test -f 'src/libostree/ostree-chain-input-stream.c' || echo '$(srcdir)/'`src/libostree/ostree-chain-input-stream.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-chain-input-stream.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-chain-input-stream.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-chain-input-stream.c' object='src/libostree/libostree_1_la-ostree-chain-input-stream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-chain-input-stream.lo `test -f 'src/libostree/ostree-chain-input-stream.c' || echo '$(srcdir)/'`src/libostree/ostree-chain-input-stream.c + +src/libostree/libostree_1_la-ostree-lzma-common.lo: src/libostree/ostree-lzma-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-lzma-common.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-common.Tpo -c -o src/libostree/libostree_1_la-ostree-lzma-common.lo `test -f 'src/libostree/ostree-lzma-common.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-common.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-common.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-lzma-common.c' object='src/libostree/libostree_1_la-ostree-lzma-common.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-lzma-common.lo `test -f 'src/libostree/ostree-lzma-common.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-common.c + +src/libostree/libostree_1_la-ostree-lzma-compressor.lo: src/libostree/ostree-lzma-compressor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-lzma-compressor.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-compressor.Tpo -c -o src/libostree/libostree_1_la-ostree-lzma-compressor.lo `test -f 'src/libostree/ostree-lzma-compressor.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-compressor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-compressor.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-compressor.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-lzma-compressor.c' object='src/libostree/libostree_1_la-ostree-lzma-compressor.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-lzma-compressor.lo `test -f 'src/libostree/ostree-lzma-compressor.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-compressor.c + +src/libostree/libostree_1_la-ostree-lzma-decompressor.lo: src/libostree/ostree-lzma-decompressor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-lzma-decompressor.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-decompressor.Tpo -c -o src/libostree/libostree_1_la-ostree-lzma-decompressor.lo `test -f 'src/libostree/ostree-lzma-decompressor.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-decompressor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-decompressor.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-decompressor.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-lzma-decompressor.c' object='src/libostree/libostree_1_la-ostree-lzma-decompressor.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-lzma-decompressor.lo `test -f 'src/libostree/ostree-lzma-decompressor.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-decompressor.c + +src/libostree/libostree_1_la-ostree-rollsum.lo: src/libostree/ostree-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-rollsum.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Tpo -c -o src/libostree/libostree_1_la-ostree-rollsum.lo `test -f 'src/libostree/ostree-rollsum.c' || echo '$(srcdir)/'`src/libostree/ostree-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-rollsum.c' object='src/libostree/libostree_1_la-ostree-rollsum.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-rollsum.lo `test -f 'src/libostree/ostree-rollsum.c' || echo '$(srcdir)/'`src/libostree/ostree-rollsum.c + +src/libostree/libostree_1_la-ostree-varint.lo: src/libostree/ostree-varint.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-varint.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-varint.Tpo -c -o src/libostree/libostree_1_la-ostree-varint.lo `test -f 'src/libostree/ostree-varint.c' || echo '$(srcdir)/'`src/libostree/ostree-varint.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-varint.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-varint.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-varint.c' object='src/libostree/libostree_1_la-ostree-varint.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-varint.lo `test -f 'src/libostree/ostree-varint.c' || echo '$(srcdir)/'`src/libostree/ostree-varint.c + +src/libostree/libostree_1_la-ostree-linuxfsutil.lo: src/libostree/ostree-linuxfsutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-linuxfsutil.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-linuxfsutil.Tpo -c -o src/libostree/libostree_1_la-ostree-linuxfsutil.lo `test -f 'src/libostree/ostree-linuxfsutil.c' || echo '$(srcdir)/'`src/libostree/ostree-linuxfsutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-linuxfsutil.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-linuxfsutil.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-linuxfsutil.c' object='src/libostree/libostree_1_la-ostree-linuxfsutil.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-linuxfsutil.lo `test -f 'src/libostree/ostree-linuxfsutil.c' || echo '$(srcdir)/'`src/libostree/ostree-linuxfsutil.c + +src/libostree/libostree_1_la-ostree-diff.lo: src/libostree/ostree-diff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-diff.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-diff.Tpo -c -o src/libostree/libostree_1_la-ostree-diff.lo `test -f 'src/libostree/ostree-diff.c' || echo '$(srcdir)/'`src/libostree/ostree-diff.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-diff.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-diff.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-diff.c' object='src/libostree/libostree_1_la-ostree-diff.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-diff.lo `test -f 'src/libostree/ostree-diff.c' || echo '$(srcdir)/'`src/libostree/ostree-diff.c + +src/libostree/libostree_1_la-ostree-mutable-tree.lo: src/libostree/ostree-mutable-tree.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-mutable-tree.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-mutable-tree.Tpo -c -o src/libostree/libostree_1_la-ostree-mutable-tree.lo `test -f 'src/libostree/ostree-mutable-tree.c' || echo '$(srcdir)/'`src/libostree/ostree-mutable-tree.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-mutable-tree.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-mutable-tree.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-mutable-tree.c' object='src/libostree/libostree_1_la-ostree-mutable-tree.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-mutable-tree.lo `test -f 'src/libostree/ostree-mutable-tree.c' || echo '$(srcdir)/'`src/libostree/ostree-mutable-tree.c + +src/libostree/libostree_1_la-ostree-ref.lo: src/libostree/ostree-ref.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-ref.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-ref.Tpo -c -o src/libostree/libostree_1_la-ostree-ref.lo `test -f 'src/libostree/ostree-ref.c' || echo '$(srcdir)/'`src/libostree/ostree-ref.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-ref.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-ref.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-ref.c' object='src/libostree/libostree_1_la-ostree-ref.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-ref.lo `test -f 'src/libostree/ostree-ref.c' || echo '$(srcdir)/'`src/libostree/ostree-ref.c + +src/libostree/libostree_1_la-ostree-remote.lo: src/libostree/ostree-remote.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-remote.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Tpo -c -o src/libostree/libostree_1_la-ostree-remote.lo `test -f 'src/libostree/ostree-remote.c' || echo '$(srcdir)/'`src/libostree/ostree-remote.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-remote.c' object='src/libostree/libostree_1_la-ostree-remote.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-remote.lo `test -f 'src/libostree/ostree-remote.c' || echo '$(srcdir)/'`src/libostree/ostree-remote.c + +src/libostree/libostree_1_la-ostree-repo.lo: src/libostree/ostree-repo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Tpo -c -o src/libostree/libostree_1_la-ostree-repo.lo `test -f 'src/libostree/ostree-repo.c' || echo '$(srcdir)/'`src/libostree/ostree-repo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo.c' object='src/libostree/libostree_1_la-ostree-repo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo.lo `test -f 'src/libostree/ostree-repo.c' || echo '$(srcdir)/'`src/libostree/ostree-repo.c + +src/libostree/libostree_1_la-ostree-repo-checkout.lo: src/libostree/ostree-repo-checkout.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-checkout.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-checkout.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-checkout.lo `test -f 'src/libostree/ostree-repo-checkout.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-checkout.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-checkout.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-checkout.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-checkout.c' object='src/libostree/libostree_1_la-ostree-repo-checkout.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-checkout.lo `test -f 'src/libostree/ostree-repo-checkout.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-checkout.c + +src/libostree/libostree_1_la-ostree-repo-commit.lo: src/libostree/ostree-repo-commit.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-commit.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-commit.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-commit.lo `test -f 'src/libostree/ostree-repo-commit.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-commit.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-commit.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-commit.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-commit.c' object='src/libostree/libostree_1_la-ostree-repo-commit.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-commit.lo `test -f 'src/libostree/ostree-repo-commit.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-commit.c + +src/libostree/libostree_1_la-ostree-repo-pull.lo: src/libostree/ostree-repo-pull.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-pull.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-pull.lo `test -f 'src/libostree/ostree-repo-pull.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-pull.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-pull.c' object='src/libostree/libostree_1_la-ostree-repo-pull.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-pull.lo `test -f 'src/libostree/ostree-repo-pull.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-pull.c + +src/libostree/libostree_1_la-ostree-repo-pull-verify.lo: src/libostree/ostree-repo-pull-verify.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-pull-verify.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-pull-verify.lo `test -f 'src/libostree/ostree-repo-pull-verify.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-pull-verify.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-pull-verify.c' object='src/libostree/libostree_1_la-ostree-repo-pull-verify.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-pull-verify.lo `test -f 'src/libostree/ostree-repo-pull-verify.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-pull-verify.c + +src/libostree/libostree_1_la-ostree-repo-libarchive.lo: src/libostree/ostree-repo-libarchive.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-libarchive.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-libarchive.lo `test -f 'src/libostree/ostree-repo-libarchive.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-libarchive.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-libarchive.c' object='src/libostree/libostree_1_la-ostree-repo-libarchive.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-libarchive.lo `test -f 'src/libostree/ostree-repo-libarchive.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-libarchive.c + +src/libostree/libostree_1_la-ostree-repo-prune.lo: src/libostree/ostree-repo-prune.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-prune.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-prune.lo `test -f 'src/libostree/ostree-repo-prune.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-prune.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-prune.c' object='src/libostree/libostree_1_la-ostree-repo-prune.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-prune.lo `test -f 'src/libostree/ostree-repo-prune.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-prune.c + +src/libostree/libostree_1_la-ostree-repo-refs.lo: src/libostree/ostree-repo-refs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-refs.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-refs.lo `test -f 'src/libostree/ostree-repo-refs.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-refs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-refs.c' object='src/libostree/libostree_1_la-ostree-repo-refs.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-refs.lo `test -f 'src/libostree/ostree-repo-refs.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-refs.c + +src/libostree/libostree_1_la-ostree-repo-traverse.lo: src/libostree/ostree-repo-traverse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-traverse.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-traverse.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-traverse.lo `test -f 'src/libostree/ostree-repo-traverse.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-traverse.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-traverse.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-traverse.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-traverse.c' object='src/libostree/libostree_1_la-ostree-repo-traverse.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-traverse.lo `test -f 'src/libostree/ostree-repo-traverse.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-traverse.c + +src/libostree/libostree_1_la-ostree-repo-file.lo: src/libostree/ostree-repo-file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-file.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-file.lo `test -f 'src/libostree/ostree-repo-file.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-file.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-file.c' object='src/libostree/libostree_1_la-ostree-repo-file.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-file.lo `test -f 'src/libostree/ostree-repo-file.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-file.c + +src/libostree/libostree_1_la-ostree-repo-file-enumerator.lo: src/libostree/ostree-repo-file-enumerator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-file-enumerator.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file-enumerator.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-file-enumerator.lo `test -f 'src/libostree/ostree-repo-file-enumerator.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-file-enumerator.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file-enumerator.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file-enumerator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-file-enumerator.c' object='src/libostree/libostree_1_la-ostree-repo-file-enumerator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-file-enumerator.lo `test -f 'src/libostree/ostree-repo-file-enumerator.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-file-enumerator.c + +src/libostree/libostree_1_la-ostree-sepolicy.lo: src/libostree/ostree-sepolicy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sepolicy.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Tpo -c -o src/libostree/libostree_1_la-ostree-sepolicy.lo `test -f 'src/libostree/ostree-sepolicy.c' || echo '$(srcdir)/'`src/libostree/ostree-sepolicy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sepolicy.c' object='src/libostree/libostree_1_la-ostree-sepolicy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sepolicy.lo `test -f 'src/libostree/ostree-sepolicy.c' || echo '$(srcdir)/'`src/libostree/ostree-sepolicy.c + +src/libostree/libostree_1_la-ostree-sysroot.lo: src/libostree/ostree-sysroot.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sysroot.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot.Tpo -c -o src/libostree/libostree_1_la-ostree-sysroot.lo `test -f 'src/libostree/ostree-sysroot.c' || echo '$(srcdir)/'`src/libostree/ostree-sysroot.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sysroot.c' object='src/libostree/libostree_1_la-ostree-sysroot.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sysroot.lo `test -f 'src/libostree/ostree-sysroot.c' || echo '$(srcdir)/'`src/libostree/ostree-sysroot.c + +src/libostree/libostree_1_la-ostree-sysroot-cleanup.lo: src/libostree/ostree-sysroot-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sysroot-cleanup.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Tpo -c -o src/libostree/libostree_1_la-ostree-sysroot-cleanup.lo `test -f 'src/libostree/ostree-sysroot-cleanup.c' || echo '$(srcdir)/'`src/libostree/ostree-sysroot-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sysroot-cleanup.c' object='src/libostree/libostree_1_la-ostree-sysroot-cleanup.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sysroot-cleanup.lo `test -f 'src/libostree/ostree-sysroot-cleanup.c' || echo '$(srcdir)/'`src/libostree/ostree-sysroot-cleanup.c + +src/libostree/libostree_1_la-ostree-sysroot-deploy.lo: src/libostree/ostree-sysroot-deploy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sysroot-deploy.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-deploy.Tpo -c -o src/libostree/libostree_1_la-ostree-sysroot-deploy.lo `test -f 'src/libostree/ostree-sysroot-deploy.c' || echo '$(srcdir)/'`src/libostree/ostree-sysroot-deploy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-deploy.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-deploy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sysroot-deploy.c' object='src/libostree/libostree_1_la-ostree-sysroot-deploy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sysroot-deploy.lo `test -f 'src/libostree/ostree-sysroot-deploy.c' || echo '$(srcdir)/'`src/libostree/ostree-sysroot-deploy.c + +src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo: src/libostree/ostree-sysroot-upgrader.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-upgrader.Tpo -c -o src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo `test -f 'src/libostree/ostree-sysroot-upgrader.c' || echo '$(srcdir)/'`src/libostree/ostree-sysroot-upgrader.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-upgrader.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-upgrader.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sysroot-upgrader.c' object='src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo `test -f 'src/libostree/ostree-sysroot-upgrader.c' || echo '$(srcdir)/'`src/libostree/ostree-sysroot-upgrader.c + +src/libostree/libostree_1_la-ostree-impl-system-generator.lo: src/libostree/ostree-impl-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-impl-system-generator.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Tpo -c -o src/libostree/libostree_1_la-ostree-impl-system-generator.lo `test -f 'src/libostree/ostree-impl-system-generator.c' || echo '$(srcdir)/'`src/libostree/ostree-impl-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-impl-system-generator.c' object='src/libostree/libostree_1_la-ostree-impl-system-generator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-impl-system-generator.lo `test -f 'src/libostree/ostree-impl-system-generator.c' || echo '$(srcdir)/'`src/libostree/ostree-impl-system-generator.c + +src/libostree/libostree_1_la-ostree-bootconfig-parser.lo: src/libostree/ostree-bootconfig-parser.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-bootconfig-parser.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Tpo -c -o src/libostree/libostree_1_la-ostree-bootconfig-parser.lo `test -f 'src/libostree/ostree-bootconfig-parser.c' || echo '$(srcdir)/'`src/libostree/ostree-bootconfig-parser.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-bootconfig-parser.c' object='src/libostree/libostree_1_la-ostree-bootconfig-parser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-bootconfig-parser.lo `test -f 'src/libostree/ostree-bootconfig-parser.c' || echo '$(srcdir)/'`src/libostree/ostree-bootconfig-parser.c + +src/libostree/libostree_1_la-ostree-deployment.lo: src/libostree/ostree-deployment.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-deployment.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-deployment.Tpo -c -o src/libostree/libostree_1_la-ostree-deployment.lo `test -f 'src/libostree/ostree-deployment.c' || echo '$(srcdir)/'`src/libostree/ostree-deployment.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-deployment.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-deployment.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-deployment.c' object='src/libostree/libostree_1_la-ostree-deployment.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-deployment.lo `test -f 'src/libostree/ostree-deployment.c' || echo '$(srcdir)/'`src/libostree/ostree-deployment.c + +src/libostree/libostree_1_la-ostree-bootloader.lo: src/libostree/ostree-bootloader.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-bootloader.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader.Tpo -c -o src/libostree/libostree_1_la-ostree-bootloader.lo `test -f 'src/libostree/ostree-bootloader.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-bootloader.c' object='src/libostree/libostree_1_la-ostree-bootloader.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-bootloader.lo `test -f 'src/libostree/ostree-bootloader.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader.c + +src/libostree/libostree_1_la-ostree-bootloader-grub2.lo: src/libostree/ostree-bootloader-grub2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-bootloader-grub2.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-grub2.Tpo -c -o src/libostree/libostree_1_la-ostree-bootloader-grub2.lo `test -f 'src/libostree/ostree-bootloader-grub2.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader-grub2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-grub2.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-grub2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-bootloader-grub2.c' object='src/libostree/libostree_1_la-ostree-bootloader-grub2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-bootloader-grub2.lo `test -f 'src/libostree/ostree-bootloader-grub2.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader-grub2.c + +src/libostree/libostree_1_la-ostree-bootloader-zipl.lo: src/libostree/ostree-bootloader-zipl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-bootloader-zipl.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-zipl.Tpo -c -o src/libostree/libostree_1_la-ostree-bootloader-zipl.lo `test -f 'src/libostree/ostree-bootloader-zipl.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader-zipl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-zipl.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-zipl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-bootloader-zipl.c' object='src/libostree/libostree_1_la-ostree-bootloader-zipl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-bootloader-zipl.lo `test -f 'src/libostree/ostree-bootloader-zipl.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader-zipl.c + +src/libostree/libostree_1_la-ostree-bootloader-syslinux.lo: src/libostree/ostree-bootloader-syslinux.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-bootloader-syslinux.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-syslinux.Tpo -c -o src/libostree/libostree_1_la-ostree-bootloader-syslinux.lo `test -f 'src/libostree/ostree-bootloader-syslinux.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader-syslinux.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-syslinux.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-syslinux.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-bootloader-syslinux.c' object='src/libostree/libostree_1_la-ostree-bootloader-syslinux.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-bootloader-syslinux.lo `test -f 'src/libostree/ostree-bootloader-syslinux.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader-syslinux.c + +src/libostree/libostree_1_la-ostree-bootloader-uboot.lo: src/libostree/ostree-bootloader-uboot.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-bootloader-uboot.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-uboot.Tpo -c -o src/libostree/libostree_1_la-ostree-bootloader-uboot.lo `test -f 'src/libostree/ostree-bootloader-uboot.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader-uboot.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-uboot.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-uboot.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-bootloader-uboot.c' object='src/libostree/libostree_1_la-ostree-bootloader-uboot.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-bootloader-uboot.lo `test -f 'src/libostree/ostree-bootloader-uboot.c' || echo '$(srcdir)/'`src/libostree/ostree-bootloader-uboot.c + +src/libostree/libostree_1_la-ostree-repo-static-delta-core.lo: src/libostree/ostree-repo-static-delta-core.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-static-delta-core.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-core.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-static-delta-core.lo `test -f 'src/libostree/ostree-repo-static-delta-core.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-static-delta-core.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-core.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-core.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-static-delta-core.c' object='src/libostree/libostree_1_la-ostree-repo-static-delta-core.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-static-delta-core.lo `test -f 'src/libostree/ostree-repo-static-delta-core.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-static-delta-core.c + +src/libostree/libostree_1_la-ostree-repo-static-delta-processing.lo: src/libostree/ostree-repo-static-delta-processing.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-static-delta-processing.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-processing.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-static-delta-processing.lo `test -f 'src/libostree/ostree-repo-static-delta-processing.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-static-delta-processing.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-processing.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-processing.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-static-delta-processing.c' object='src/libostree/libostree_1_la-ostree-repo-static-delta-processing.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-static-delta-processing.lo `test -f 'src/libostree/ostree-repo-static-delta-processing.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-static-delta-processing.c + +src/libostree/libostree_1_la-ostree-repo-static-delta-compilation.lo: src/libostree/ostree-repo-static-delta-compilation.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-static-delta-compilation.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-static-delta-compilation.lo `test -f 'src/libostree/ostree-repo-static-delta-compilation.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-static-delta-compilation.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-static-delta-compilation.c' object='src/libostree/libostree_1_la-ostree-repo-static-delta-compilation.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-static-delta-compilation.lo `test -f 'src/libostree/ostree-repo-static-delta-compilation.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-static-delta-compilation.c + +src/libostree/libostree_1_la-ostree-repo-static-delta-compilation-analysis.lo: src/libostree/ostree-repo-static-delta-compilation-analysis.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-static-delta-compilation-analysis.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-static-delta-compilation-analysis.lo `test -f 'src/libostree/ostree-repo-static-delta-compilation-analysis.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-static-delta-compilation-analysis.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-static-delta-compilation-analysis.c' object='src/libostree/libostree_1_la-ostree-repo-static-delta-compilation-analysis.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-static-delta-compilation-analysis.lo `test -f 'src/libostree/ostree-repo-static-delta-compilation-analysis.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-static-delta-compilation-analysis.c + +src/libostree/libostree_1_la-ostree-bloom.lo: src/libostree/ostree-bloom.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-bloom.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-bloom.Tpo -c -o src/libostree/libostree_1_la-ostree-bloom.lo `test -f 'src/libostree/ostree-bloom.c' || echo '$(srcdir)/'`src/libostree/ostree-bloom.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-bloom.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-bloom.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-bloom.c' object='src/libostree/libostree_1_la-ostree-bloom.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-bloom.lo `test -f 'src/libostree/ostree-bloom.c' || echo '$(srcdir)/'`src/libostree/ostree-bloom.c + +src/libostree/libostree_1_la-ostree-repo-finder.lo: src/libostree/ostree-repo-finder.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-finder.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-finder.lo `test -f 'src/libostree/ostree-repo-finder.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-finder.c' object='src/libostree/libostree_1_la-ostree-repo-finder.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-finder.lo `test -f 'src/libostree/ostree-repo-finder.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder.c + +src/libostree/libostree_1_la-ostree-repo-finder-avahi.lo: src/libostree/ostree-repo-finder-avahi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-finder-avahi.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-finder-avahi.lo `test -f 'src/libostree/ostree-repo-finder-avahi.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-avahi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-finder-avahi.c' object='src/libostree/libostree_1_la-ostree-repo-finder-avahi.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-finder-avahi.lo `test -f 'src/libostree/ostree-repo-finder-avahi.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-avahi.c + +src/libostree/libostree_1_la-ostree-repo-finder-config.lo: src/libostree/ostree-repo-finder-config.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-finder-config.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-config.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-finder-config.lo `test -f 'src/libostree/ostree-repo-finder-config.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-config.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-config.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-config.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-finder-config.c' object='src/libostree/libostree_1_la-ostree-repo-finder-config.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-finder-config.lo `test -f 'src/libostree/ostree-repo-finder-config.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-config.c + +src/libostree/libostree_1_la-ostree-repo-finder-mount.lo: src/libostree/ostree-repo-finder-mount.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-finder-mount.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-mount.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-finder-mount.lo `test -f 'src/libostree/ostree-repo-finder-mount.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-mount.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-mount.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-mount.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-finder-mount.c' object='src/libostree/libostree_1_la-ostree-repo-finder-mount.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-finder-mount.lo `test -f 'src/libostree/ostree-repo-finder-mount.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-mount.c + +src/libostree/libostree_1_la-ostree-repo-finder-override.lo: src/libostree/ostree-repo-finder-override.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-finder-override.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-finder-override.lo `test -f 'src/libostree/ostree-repo-finder-override.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-override.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-finder-override.c' object='src/libostree/libostree_1_la-ostree-repo-finder-override.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-finder-override.lo `test -f 'src/libostree/ostree-repo-finder-override.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-override.c + +src/libostree/libostree_1_la-ostree-kernel-args.lo: src/libostree/ostree-kernel-args.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-kernel-args.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-kernel-args.Tpo -c -o src/libostree/libostree_1_la-ostree-kernel-args.lo `test -f 'src/libostree/ostree-kernel-args.c' || echo '$(srcdir)/'`src/libostree/ostree-kernel-args.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-kernel-args.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-kernel-args.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-kernel-args.c' object='src/libostree/libostree_1_la-ostree-kernel-args.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-kernel-args.lo `test -f 'src/libostree/ostree-kernel-args.c' || echo '$(srcdir)/'`src/libostree/ostree-kernel-args.c + +src/libostree/libostree_1_la-ostree-libarchive-input-stream.lo: src/libostree/ostree-libarchive-input-stream.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-libarchive-input-stream.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-libarchive-input-stream.Tpo -c -o src/libostree/libostree_1_la-ostree-libarchive-input-stream.lo `test -f 'src/libostree/ostree-libarchive-input-stream.c' || echo '$(srcdir)/'`src/libostree/ostree-libarchive-input-stream.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-libarchive-input-stream.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-libarchive-input-stream.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-libarchive-input-stream.c' object='src/libostree/libostree_1_la-ostree-libarchive-input-stream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-libarchive-input-stream.lo `test -f 'src/libostree/ostree-libarchive-input-stream.c' || echo '$(srcdir)/'`src/libostree/ostree-libarchive-input-stream.c + +src/libostree/libostree_1_la-ostree-tls-cert-interaction.lo: src/libostree/ostree-tls-cert-interaction.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-tls-cert-interaction.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-tls-cert-interaction.Tpo -c -o src/libostree/libostree_1_la-ostree-tls-cert-interaction.lo `test -f 'src/libostree/ostree-tls-cert-interaction.c' || echo '$(srcdir)/'`src/libostree/ostree-tls-cert-interaction.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-tls-cert-interaction.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-tls-cert-interaction.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-tls-cert-interaction.c' object='src/libostree/libostree_1_la-ostree-tls-cert-interaction.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-tls-cert-interaction.lo `test -f 'src/libostree/ostree-tls-cert-interaction.c' || echo '$(srcdir)/'`src/libostree/ostree-tls-cert-interaction.c + +src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo: src/libostree/ostree-repo-finder-avahi-parser.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Tpo -c -o src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo `test -f 'src/libostree/ostree-repo-finder-avahi-parser.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-avahi-parser.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-finder-avahi-parser.c' object='src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-repo-finder-avahi-parser.lo `test -f 'src/libostree/ostree-repo-finder-avahi-parser.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-avahi-parser.c + +src/libostree/libostree_1_la-ostree-gpg-verifier.lo: src/libostree/ostree-gpg-verifier.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-gpg-verifier.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verifier.Tpo -c -o src/libostree/libostree_1_la-ostree-gpg-verifier.lo `test -f 'src/libostree/ostree-gpg-verifier.c' || echo '$(srcdir)/'`src/libostree/ostree-gpg-verifier.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verifier.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verifier.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-gpg-verifier.c' object='src/libostree/libostree_1_la-ostree-gpg-verifier.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-gpg-verifier.lo `test -f 'src/libostree/ostree-gpg-verifier.c' || echo '$(srcdir)/'`src/libostree/ostree-gpg-verifier.c + +src/libostree/libostree_1_la-ostree-gpg-verify-result.lo: src/libostree/ostree-gpg-verify-result.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-gpg-verify-result.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result.Tpo -c -o src/libostree/libostree_1_la-ostree-gpg-verify-result.lo `test -f 'src/libostree/ostree-gpg-verify-result.c' || echo '$(srcdir)/'`src/libostree/ostree-gpg-verify-result.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-gpg-verify-result.c' object='src/libostree/libostree_1_la-ostree-gpg-verify-result.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-gpg-verify-result.lo `test -f 'src/libostree/ostree-gpg-verify-result.c' || echo '$(srcdir)/'`src/libostree/ostree-gpg-verify-result.c + +src/libostree/libostree_1_la-ostree-gpg-verify-result-dummy.lo: src/libostree/ostree-gpg-verify-result-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-gpg-verify-result-dummy.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result-dummy.Tpo -c -o src/libostree/libostree_1_la-ostree-gpg-verify-result-dummy.lo `test -f 'src/libostree/ostree-gpg-verify-result-dummy.c' || echo '$(srcdir)/'`src/libostree/ostree-gpg-verify-result-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result-dummy.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result-dummy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-gpg-verify-result-dummy.c' object='src/libostree/libostree_1_la-ostree-gpg-verify-result-dummy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-gpg-verify-result-dummy.lo `test -f 'src/libostree/ostree-gpg-verify-result-dummy.c' || echo '$(srcdir)/'`src/libostree/ostree-gpg-verify-result-dummy.c + +src/libostree/libostree_1_la-ostree-fetcher-util.lo: src/libostree/ostree-fetcher-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-fetcher-util.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-util.Tpo -c -o src/libostree/libostree_1_la-ostree-fetcher-util.lo `test -f 'src/libostree/ostree-fetcher-util.c' || echo '$(srcdir)/'`src/libostree/ostree-fetcher-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-util.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-fetcher-util.c' object='src/libostree/libostree_1_la-ostree-fetcher-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-fetcher-util.lo `test -f 'src/libostree/ostree-fetcher-util.c' || echo '$(srcdir)/'`src/libostree/ostree-fetcher-util.c + +src/libostree/libostree_1_la-ostree-fetcher-uri.lo: src/libostree/ostree-fetcher-uri.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-fetcher-uri.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-uri.Tpo -c -o src/libostree/libostree_1_la-ostree-fetcher-uri.lo `test -f 'src/libostree/ostree-fetcher-uri.c' || echo '$(srcdir)/'`src/libostree/ostree-fetcher-uri.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-uri.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-uri.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-fetcher-uri.c' object='src/libostree/libostree_1_la-ostree-fetcher-uri.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-fetcher-uri.lo `test -f 'src/libostree/ostree-fetcher-uri.c' || echo '$(srcdir)/'`src/libostree/ostree-fetcher-uri.c + +src/libostree/libostree_1_la-ostree-metalink.lo: src/libostree/ostree-metalink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-metalink.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-metalink.Tpo -c -o src/libostree/libostree_1_la-ostree-metalink.lo `test -f 'src/libostree/ostree-metalink.c' || echo '$(srcdir)/'`src/libostree/ostree-metalink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-metalink.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-metalink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-metalink.c' object='src/libostree/libostree_1_la-ostree-metalink.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-metalink.lo `test -f 'src/libostree/ostree-metalink.c' || echo '$(srcdir)/'`src/libostree/ostree-metalink.c + +src/libostree/libostree_1_la-ostree-fetcher-curl.lo: src/libostree/ostree-fetcher-curl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-fetcher-curl.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-curl.Tpo -c -o src/libostree/libostree_1_la-ostree-fetcher-curl.lo `test -f 'src/libostree/ostree-fetcher-curl.c' || echo '$(srcdir)/'`src/libostree/ostree-fetcher-curl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-curl.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-curl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-fetcher-curl.c' object='src/libostree/libostree_1_la-ostree-fetcher-curl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-fetcher-curl.lo `test -f 'src/libostree/ostree-fetcher-curl.c' || echo '$(srcdir)/'`src/libostree/ostree-fetcher-curl.c + +src/libostree/libostree_1_la-ostree-soup-uri.lo: src/libostree/ostree-soup-uri.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-soup-uri.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Tpo -c -o src/libostree/libostree_1_la-ostree-soup-uri.lo `test -f 'src/libostree/ostree-soup-uri.c' || echo '$(srcdir)/'`src/libostree/ostree-soup-uri.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-soup-uri.c' object='src/libostree/libostree_1_la-ostree-soup-uri.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-soup-uri.lo `test -f 'src/libostree/ostree-soup-uri.c' || echo '$(srcdir)/'`src/libostree/ostree-soup-uri.c + +src/libostree/libostree_1_la-ostree-soup-form.lo: src/libostree/ostree-soup-form.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-soup-form.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Tpo -c -o src/libostree/libostree_1_la-ostree-soup-form.lo `test -f 'src/libostree/ostree-soup-form.c' || echo '$(srcdir)/'`src/libostree/ostree-soup-form.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-soup-form.c' object='src/libostree/libostree_1_la-ostree-soup-form.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-soup-form.lo `test -f 'src/libostree/ostree-soup-form.c' || echo '$(srcdir)/'`src/libostree/ostree-soup-form.c + +src/libostree/libostree_1_la-ostree-fetcher-soup.lo: src/libostree/ostree-fetcher-soup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-fetcher-soup.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-soup.Tpo -c -o src/libostree/libostree_1_la-ostree-fetcher-soup.lo `test -f 'src/libostree/ostree-fetcher-soup.c' || echo '$(srcdir)/'`src/libostree/ostree-fetcher-soup.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-soup.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-soup.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-fetcher-soup.c' object='src/libostree/libostree_1_la-ostree-fetcher-soup.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-fetcher-soup.lo `test -f 'src/libostree/ostree-fetcher-soup.c' || echo '$(srcdir)/'`src/libostree/ostree-fetcher-soup.c + +src/libostree/libostree_1_la-ostree-sign.lo: src/libostree/ostree-sign.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sign.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Tpo -c -o src/libostree/libostree_1_la-ostree-sign.lo `test -f 'src/libostree/ostree-sign.c' || echo '$(srcdir)/'`src/libostree/ostree-sign.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sign.c' object='src/libostree/libostree_1_la-ostree-sign.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sign.lo `test -f 'src/libostree/ostree-sign.c' || echo '$(srcdir)/'`src/libostree/ostree-sign.c + +src/libostree/libostree_1_la-ostree-sign-dummy.lo: src/libostree/ostree-sign-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sign-dummy.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Tpo -c -o src/libostree/libostree_1_la-ostree-sign-dummy.lo `test -f 'src/libostree/ostree-sign-dummy.c' || echo '$(srcdir)/'`src/libostree/ostree-sign-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sign-dummy.c' object='src/libostree/libostree_1_la-ostree-sign-dummy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sign-dummy.lo `test -f 'src/libostree/ostree-sign-dummy.c' || echo '$(srcdir)/'`src/libostree/ostree-sign-dummy.c + +src/libostree/libostree_1_la-ostree-sign-ed25519.lo: src/libostree/ostree-sign-ed25519.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-sign-ed25519.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Tpo -c -o src/libostree/libostree_1_la-ostree-sign-ed25519.lo `test -f 'src/libostree/ostree-sign-ed25519.c' || echo '$(srcdir)/'`src/libostree/ostree-sign-ed25519.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-sign-ed25519.c' object='src/libostree/libostree_1_la-ostree-sign-ed25519.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sign-ed25519.lo `test -f 'src/libostree/ostree-sign-ed25519.c' || echo '$(srcdir)/'`src/libostree/ostree-sign-ed25519.c + +src/libostree/libostree_1_la-ostree-enumtypes.lo: src/libostree/ostree-enumtypes.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-enumtypes.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Tpo -c -o src/libostree/libostree_1_la-ostree-enumtypes.lo `test -f 'src/libostree/ostree-enumtypes.c' || echo '$(srcdir)/'`src/libostree/ostree-enumtypes.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-enumtypes.c' object='src/libostree/libostree_1_la-ostree-enumtypes.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-enumtypes.lo `test -f 'src/libostree/ostree-enumtypes.c' || echo '$(srcdir)/'`src/libostree/ostree-enumtypes.c + +tests/libostreetest_la-libostreetest.lo: tests/libostreetest.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostreetest_la_CFLAGS) $(CFLAGS) -MT tests/libostreetest_la-libostreetest.lo -MD -MP -MF tests/$(DEPDIR)/libostreetest_la-libostreetest.Tpo -c -o tests/libostreetest_la-libostreetest.lo `test -f 'tests/libostreetest.c' || echo '$(srcdir)/'`tests/libostreetest.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/libostreetest_la-libostreetest.Tpo tests/$(DEPDIR)/libostreetest_la-libostreetest.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/libostreetest.c' object='tests/libostreetest_la-libostreetest.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostreetest_la_CFLAGS) $(CFLAGS) -c -o tests/libostreetest_la-libostreetest.lo `test -f 'tests/libostreetest.c' || echo '$(srcdir)/'`tests/libostreetest.c + +tests/libostreetest_la-test-mock-gio.lo: tests/test-mock-gio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostreetest_la_CFLAGS) $(CFLAGS) -MT tests/libostreetest_la-test-mock-gio.lo -MD -MP -MF tests/$(DEPDIR)/libostreetest_la-test-mock-gio.Tpo -c -o tests/libostreetest_la-test-mock-gio.lo `test -f 'tests/test-mock-gio.c' || echo '$(srcdir)/'`tests/test-mock-gio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/libostreetest_la-test-mock-gio.Tpo tests/$(DEPDIR)/libostreetest_la-test-mock-gio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-mock-gio.c' object='tests/libostreetest_la-test-mock-gio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostreetest_la_CFLAGS) $(CFLAGS) -c -o tests/libostreetest_la-test-mock-gio.lo `test -f 'tests/test-mock-gio.c' || echo '$(srcdir)/'`tests/test-mock-gio.c + +src/libotutil/libotutil_la-ot-checksum-utils.lo: src/libotutil/ot-checksum-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-checksum-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-utils.Tpo -c -o src/libotutil/libotutil_la-ot-checksum-utils.lo `test -f 'src/libotutil/ot-checksum-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-checksum-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-checksum-utils.c' object='src/libotutil/libotutil_la-ot-checksum-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-checksum-utils.lo `test -f 'src/libotutil/ot-checksum-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-checksum-utils.c + +src/libotutil/libotutil_la-ot-checksum-instream.lo: src/libotutil/ot-checksum-instream.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-checksum-instream.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-instream.Tpo -c -o src/libotutil/libotutil_la-ot-checksum-instream.lo `test -f 'src/libotutil/ot-checksum-instream.c' || echo '$(srcdir)/'`src/libotutil/ot-checksum-instream.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-instream.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-instream.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-checksum-instream.c' object='src/libotutil/libotutil_la-ot-checksum-instream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-checksum-instream.lo `test -f 'src/libotutil/ot-checksum-instream.c' || echo '$(srcdir)/'`src/libotutil/ot-checksum-instream.c + +src/libotutil/libotutil_la-ot-fs-utils.lo: src/libotutil/ot-fs-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-fs-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-fs-utils.Tpo -c -o src/libotutil/libotutil_la-ot-fs-utils.lo `test -f 'src/libotutil/ot-fs-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-fs-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-fs-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-fs-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-fs-utils.c' object='src/libotutil/libotutil_la-ot-fs-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-fs-utils.lo `test -f 'src/libotutil/ot-fs-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-fs-utils.c + +src/libotutil/libotutil_la-ot-keyfile-utils.lo: src/libotutil/ot-keyfile-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-keyfile-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-keyfile-utils.Tpo -c -o src/libotutil/libotutil_la-ot-keyfile-utils.lo `test -f 'src/libotutil/ot-keyfile-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-keyfile-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-keyfile-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-keyfile-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-keyfile-utils.c' object='src/libotutil/libotutil_la-ot-keyfile-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-keyfile-utils.lo `test -f 'src/libotutil/ot-keyfile-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-keyfile-utils.c + +src/libotutil/libotutil_la-ot-opt-utils.lo: src/libotutil/ot-opt-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-opt-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Tpo -c -o src/libotutil/libotutil_la-ot-opt-utils.lo `test -f 'src/libotutil/ot-opt-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-opt-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-opt-utils.c' object='src/libotutil/libotutil_la-ot-opt-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-opt-utils.lo `test -f 'src/libotutil/ot-opt-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-opt-utils.c + +src/libotutil/libotutil_la-ot-unix-utils.lo: src/libotutil/ot-unix-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-unix-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Tpo -c -o src/libotutil/libotutil_la-ot-unix-utils.lo `test -f 'src/libotutil/ot-unix-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-unix-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-unix-utils.c' object='src/libotutil/libotutil_la-ot-unix-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-unix-utils.lo `test -f 'src/libotutil/ot-unix-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-unix-utils.c + +src/libotutil/libotutil_la-ot-variant-utils.lo: src/libotutil/ot-variant-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-variant-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-utils.Tpo -c -o src/libotutil/libotutil_la-ot-variant-utils.lo `test -f 'src/libotutil/ot-variant-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-variant-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-variant-utils.c' object='src/libotutil/libotutil_la-ot-variant-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-variant-utils.lo `test -f 'src/libotutil/ot-variant-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-variant-utils.c + +src/libotutil/libotutil_la-ot-variant-builder.lo: src/libotutil/ot-variant-builder.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-variant-builder.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Tpo -c -o src/libotutil/libotutil_la-ot-variant-builder.lo `test -f 'src/libotutil/ot-variant-builder.c' || echo '$(srcdir)/'`src/libotutil/ot-variant-builder.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-variant-builder.c' object='src/libotutil/libotutil_la-ot-variant-builder.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-variant-builder.lo `test -f 'src/libotutil/ot-variant-builder.c' || echo '$(srcdir)/'`src/libotutil/ot-variant-builder.c + +src/libotutil/libotutil_la-ot-gio-utils.lo: src/libotutil/ot-gio-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-gio-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Tpo -c -o src/libotutil/libotutil_la-ot-gio-utils.lo `test -f 'src/libotutil/ot-gio-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gio-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-gio-utils.c' object='src/libotutil/libotutil_la-ot-gio-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-gio-utils.lo `test -f 'src/libotutil/ot-gio-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gio-utils.c + +src/libotutil/libotutil_la-ot-tool-util.lo: src/libotutil/ot-tool-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-tool-util.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Tpo -c -o src/libotutil/libotutil_la-ot-tool-util.lo `test -f 'src/libotutil/ot-tool-util.c' || echo '$(srcdir)/'`src/libotutil/ot-tool-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-tool-util.c' object='src/libotutil/libotutil_la-ot-tool-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-tool-util.lo `test -f 'src/libotutil/ot-tool-util.c' || echo '$(srcdir)/'`src/libotutil/ot-tool-util.c + +src/libotutil/libotutil_la-ot-gpg-utils.lo: src/libotutil/ot-gpg-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-gpg-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Tpo -c -o src/libotutil/libotutil_la-ot-gpg-utils.lo `test -f 'src/libotutil/ot-gpg-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gpg-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-gpg-utils.c' object='src/libotutil/libotutil_la-ot-gpg-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-gpg-utils.lo `test -f 'src/libotutil/ot-gpg-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gpg-utils.c + +tests/libreaddir_rand_la-readdir-rand.lo: tests/readdir-rand.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreaddir_rand_la_CFLAGS) $(CFLAGS) -MT tests/libreaddir_rand_la-readdir-rand.lo -MD -MP -MF tests/$(DEPDIR)/libreaddir_rand_la-readdir-rand.Tpo -c -o tests/libreaddir_rand_la-readdir-rand.lo `test -f 'tests/readdir-rand.c' || echo '$(srcdir)/'`tests/readdir-rand.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/libreaddir_rand_la-readdir-rand.Tpo tests/$(DEPDIR)/libreaddir_rand_la-readdir-rand.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/readdir-rand.c' object='tests/libreaddir_rand_la-readdir-rand.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreaddir_rand_la_CFLAGS) $(CFLAGS) -c -o tests/libreaddir_rand_la-readdir-rand.lo `test -f 'tests/readdir-rand.c' || echo '$(srcdir)/'`tests/readdir-rand.c + +src/ostree/ostree-main.o: src/ostree/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-main.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-main.Tpo -c -o src/ostree/ostree-main.o `test -f 'src/ostree/main.c' || echo '$(srcdir)/'`src/ostree/main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-main.Tpo src/ostree/$(DEPDIR)/ostree-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/main.c' object='src/ostree/ostree-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-main.o `test -f 'src/ostree/main.c' || echo '$(srcdir)/'`src/ostree/main.c + +src/ostree/ostree-main.obj: src/ostree/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-main.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-main.Tpo -c -o src/ostree/ostree-main.obj `if test -f 'src/ostree/main.c'; then $(CYGPATH_W) 'src/ostree/main.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/main.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-main.Tpo src/ostree/$(DEPDIR)/ostree-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/main.c' object='src/ostree/ostree-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-main.obj `if test -f 'src/ostree/main.c'; then $(CYGPATH_W) 'src/ostree/main.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/main.c'; fi` + +src/ostree/ostree-ot-builtin-admin.o: src/ostree/ot-builtin-admin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-admin.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Tpo -c -o src/ostree/ostree-ot-builtin-admin.o `test -f 'src/ostree/ot-builtin-admin.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-admin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-admin.c' object='src/ostree/ostree-ot-builtin-admin.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-admin.o `test -f 'src/ostree/ot-builtin-admin.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-admin.c + +src/ostree/ostree-ot-builtin-admin.obj: src/ostree/ot-builtin-admin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-admin.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Tpo -c -o src/ostree/ostree-ot-builtin-admin.obj `if test -f 'src/ostree/ot-builtin-admin.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-admin.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-admin.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-admin.c' object='src/ostree/ostree-ot-builtin-admin.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-admin.obj `if test -f 'src/ostree/ot-builtin-admin.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-admin.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-admin.c'; fi` + +src/ostree/ostree-ot-builtin-cat.o: src/ostree/ot-builtin-cat.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-cat.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Tpo -c -o src/ostree/ostree-ot-builtin-cat.o `test -f 'src/ostree/ot-builtin-cat.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-cat.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-cat.c' object='src/ostree/ostree-ot-builtin-cat.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-cat.o `test -f 'src/ostree/ot-builtin-cat.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-cat.c + +src/ostree/ostree-ot-builtin-cat.obj: src/ostree/ot-builtin-cat.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-cat.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Tpo -c -o src/ostree/ostree-ot-builtin-cat.obj `if test -f 'src/ostree/ot-builtin-cat.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-cat.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-cat.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-cat.c' object='src/ostree/ostree-ot-builtin-cat.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-cat.obj `if test -f 'src/ostree/ot-builtin-cat.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-cat.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-cat.c'; fi` + +src/ostree/ostree-ot-builtin-config.o: src/ostree/ot-builtin-config.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-config.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Tpo -c -o src/ostree/ostree-ot-builtin-config.o `test -f 'src/ostree/ot-builtin-config.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-config.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-config.c' object='src/ostree/ostree-ot-builtin-config.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-config.o `test -f 'src/ostree/ot-builtin-config.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-config.c + +src/ostree/ostree-ot-builtin-config.obj: src/ostree/ot-builtin-config.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-config.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Tpo -c -o src/ostree/ostree-ot-builtin-config.obj `if test -f 'src/ostree/ot-builtin-config.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-config.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-config.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-config.c' object='src/ostree/ostree-ot-builtin-config.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-config.obj `if test -f 'src/ostree/ot-builtin-config.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-config.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-config.c'; fi` + +src/ostree/ostree-ot-builtin-checkout.o: src/ostree/ot-builtin-checkout.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-checkout.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Tpo -c -o src/ostree/ostree-ot-builtin-checkout.o `test -f 'src/ostree/ot-builtin-checkout.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-checkout.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-checkout.c' object='src/ostree/ostree-ot-builtin-checkout.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-checkout.o `test -f 'src/ostree/ot-builtin-checkout.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-checkout.c + +src/ostree/ostree-ot-builtin-checkout.obj: src/ostree/ot-builtin-checkout.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-checkout.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Tpo -c -o src/ostree/ostree-ot-builtin-checkout.obj `if test -f 'src/ostree/ot-builtin-checkout.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-checkout.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-checkout.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-checkout.c' object='src/ostree/ostree-ot-builtin-checkout.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-checkout.obj `if test -f 'src/ostree/ot-builtin-checkout.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-checkout.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-checkout.c'; fi` + +src/ostree/ostree-ot-builtin-checksum.o: src/ostree/ot-builtin-checksum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-checksum.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Tpo -c -o src/ostree/ostree-ot-builtin-checksum.o `test -f 'src/ostree/ot-builtin-checksum.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-checksum.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-checksum.c' object='src/ostree/ostree-ot-builtin-checksum.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-checksum.o `test -f 'src/ostree/ot-builtin-checksum.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-checksum.c + +src/ostree/ostree-ot-builtin-checksum.obj: src/ostree/ot-builtin-checksum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-checksum.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Tpo -c -o src/ostree/ostree-ot-builtin-checksum.obj `if test -f 'src/ostree/ot-builtin-checksum.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-checksum.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-checksum.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-checksum.c' object='src/ostree/ostree-ot-builtin-checksum.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-checksum.obj `if test -f 'src/ostree/ot-builtin-checksum.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-checksum.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-checksum.c'; fi` + +src/ostree/ostree-ot-builtin-commit.o: src/ostree/ot-builtin-commit.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-commit.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Tpo -c -o src/ostree/ostree-ot-builtin-commit.o `test -f 'src/ostree/ot-builtin-commit.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-commit.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-commit.c' object='src/ostree/ostree-ot-builtin-commit.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-commit.o `test -f 'src/ostree/ot-builtin-commit.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-commit.c + +src/ostree/ostree-ot-builtin-commit.obj: src/ostree/ot-builtin-commit.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-commit.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Tpo -c -o src/ostree/ostree-ot-builtin-commit.obj `if test -f 'src/ostree/ot-builtin-commit.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-commit.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-commit.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-commit.c' object='src/ostree/ostree-ot-builtin-commit.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-commit.obj `if test -f 'src/ostree/ot-builtin-commit.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-commit.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-commit.c'; fi` + +src/ostree/ostree-ot-builtin-create-usb.o: src/ostree/ot-builtin-create-usb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-create-usb.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Tpo -c -o src/ostree/ostree-ot-builtin-create-usb.o `test -f 'src/ostree/ot-builtin-create-usb.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-create-usb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-create-usb.c' object='src/ostree/ostree-ot-builtin-create-usb.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-create-usb.o `test -f 'src/ostree/ot-builtin-create-usb.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-create-usb.c + +src/ostree/ostree-ot-builtin-create-usb.obj: src/ostree/ot-builtin-create-usb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-create-usb.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Tpo -c -o src/ostree/ostree-ot-builtin-create-usb.obj `if test -f 'src/ostree/ot-builtin-create-usb.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-create-usb.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-create-usb.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-create-usb.c' object='src/ostree/ostree-ot-builtin-create-usb.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-create-usb.obj `if test -f 'src/ostree/ot-builtin-create-usb.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-create-usb.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-create-usb.c'; fi` + +src/ostree/ostree-ot-builtin-diff.o: src/ostree/ot-builtin-diff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-diff.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Tpo -c -o src/ostree/ostree-ot-builtin-diff.o `test -f 'src/ostree/ot-builtin-diff.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-diff.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-diff.c' object='src/ostree/ostree-ot-builtin-diff.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-diff.o `test -f 'src/ostree/ot-builtin-diff.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-diff.c + +src/ostree/ostree-ot-builtin-diff.obj: src/ostree/ot-builtin-diff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-diff.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Tpo -c -o src/ostree/ostree-ot-builtin-diff.obj `if test -f 'src/ostree/ot-builtin-diff.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-diff.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-diff.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-diff.c' object='src/ostree/ostree-ot-builtin-diff.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-diff.obj `if test -f 'src/ostree/ot-builtin-diff.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-diff.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-diff.c'; fi` + +src/ostree/ostree-ot-builtin-export.o: src/ostree/ot-builtin-export.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-export.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Tpo -c -o src/ostree/ostree-ot-builtin-export.o `test -f 'src/ostree/ot-builtin-export.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-export.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-export.c' object='src/ostree/ostree-ot-builtin-export.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-export.o `test -f 'src/ostree/ot-builtin-export.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-export.c + +src/ostree/ostree-ot-builtin-export.obj: src/ostree/ot-builtin-export.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-export.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Tpo -c -o src/ostree/ostree-ot-builtin-export.obj `if test -f 'src/ostree/ot-builtin-export.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-export.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-export.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-export.c' object='src/ostree/ostree-ot-builtin-export.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-export.obj `if test -f 'src/ostree/ot-builtin-export.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-export.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-export.c'; fi` + +src/ostree/ostree-ot-builtin-find-remotes.o: src/ostree/ot-builtin-find-remotes.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-find-remotes.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Tpo -c -o src/ostree/ostree-ot-builtin-find-remotes.o `test -f 'src/ostree/ot-builtin-find-remotes.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-find-remotes.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-find-remotes.c' object='src/ostree/ostree-ot-builtin-find-remotes.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-find-remotes.o `test -f 'src/ostree/ot-builtin-find-remotes.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-find-remotes.c + +src/ostree/ostree-ot-builtin-find-remotes.obj: src/ostree/ot-builtin-find-remotes.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-find-remotes.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Tpo -c -o src/ostree/ostree-ot-builtin-find-remotes.obj `if test -f 'src/ostree/ot-builtin-find-remotes.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-find-remotes.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-find-remotes.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-find-remotes.c' object='src/ostree/ostree-ot-builtin-find-remotes.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-find-remotes.obj `if test -f 'src/ostree/ot-builtin-find-remotes.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-find-remotes.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-find-remotes.c'; fi` + +src/ostree/ostree-ot-builtin-fsck.o: src/ostree/ot-builtin-fsck.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-fsck.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Tpo -c -o src/ostree/ostree-ot-builtin-fsck.o `test -f 'src/ostree/ot-builtin-fsck.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-fsck.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-fsck.c' object='src/ostree/ostree-ot-builtin-fsck.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-fsck.o `test -f 'src/ostree/ot-builtin-fsck.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-fsck.c + +src/ostree/ostree-ot-builtin-fsck.obj: src/ostree/ot-builtin-fsck.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-fsck.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Tpo -c -o src/ostree/ostree-ot-builtin-fsck.obj `if test -f 'src/ostree/ot-builtin-fsck.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-fsck.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-fsck.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-fsck.c' object='src/ostree/ostree-ot-builtin-fsck.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-fsck.obj `if test -f 'src/ostree/ot-builtin-fsck.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-fsck.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-fsck.c'; fi` + +src/ostree/ostree-ot-builtin-init.o: src/ostree/ot-builtin-init.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-init.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Tpo -c -o src/ostree/ostree-ot-builtin-init.o `test -f 'src/ostree/ot-builtin-init.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-init.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-init.c' object='src/ostree/ostree-ot-builtin-init.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-init.o `test -f 'src/ostree/ot-builtin-init.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-init.c + +src/ostree/ostree-ot-builtin-init.obj: src/ostree/ot-builtin-init.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-init.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Tpo -c -o src/ostree/ostree-ot-builtin-init.obj `if test -f 'src/ostree/ot-builtin-init.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-init.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-init.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-init.c' object='src/ostree/ostree-ot-builtin-init.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-init.obj `if test -f 'src/ostree/ot-builtin-init.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-init.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-init.c'; fi` + +src/ostree/ostree-ot-builtin-pull-local.o: src/ostree/ot-builtin-pull-local.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-pull-local.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Tpo -c -o src/ostree/ostree-ot-builtin-pull-local.o `test -f 'src/ostree/ot-builtin-pull-local.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-pull-local.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-pull-local.c' object='src/ostree/ostree-ot-builtin-pull-local.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-pull-local.o `test -f 'src/ostree/ot-builtin-pull-local.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-pull-local.c + +src/ostree/ostree-ot-builtin-pull-local.obj: src/ostree/ot-builtin-pull-local.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-pull-local.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Tpo -c -o src/ostree/ostree-ot-builtin-pull-local.obj `if test -f 'src/ostree/ot-builtin-pull-local.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-pull-local.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-pull-local.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-pull-local.c' object='src/ostree/ostree-ot-builtin-pull-local.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-pull-local.obj `if test -f 'src/ostree/ot-builtin-pull-local.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-pull-local.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-pull-local.c'; fi` + +src/ostree/ostree-ot-builtin-log.o: src/ostree/ot-builtin-log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-log.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Tpo -c -o src/ostree/ostree-ot-builtin-log.o `test -f 'src/ostree/ot-builtin-log.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-log.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-log.c' object='src/ostree/ostree-ot-builtin-log.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-log.o `test -f 'src/ostree/ot-builtin-log.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-log.c + +src/ostree/ostree-ot-builtin-log.obj: src/ostree/ot-builtin-log.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-log.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Tpo -c -o src/ostree/ostree-ot-builtin-log.obj `if test -f 'src/ostree/ot-builtin-log.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-log.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-log.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-log.c' object='src/ostree/ostree-ot-builtin-log.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-log.obj `if test -f 'src/ostree/ot-builtin-log.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-log.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-log.c'; fi` + +src/ostree/ostree-ot-builtin-ls.o: src/ostree/ot-builtin-ls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-ls.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Tpo -c -o src/ostree/ostree-ot-builtin-ls.o `test -f 'src/ostree/ot-builtin-ls.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-ls.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-ls.c' object='src/ostree/ostree-ot-builtin-ls.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-ls.o `test -f 'src/ostree/ot-builtin-ls.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-ls.c + +src/ostree/ostree-ot-builtin-ls.obj: src/ostree/ot-builtin-ls.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-ls.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Tpo -c -o src/ostree/ostree-ot-builtin-ls.obj `if test -f 'src/ostree/ot-builtin-ls.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-ls.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-ls.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-ls.c' object='src/ostree/ostree-ot-builtin-ls.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-ls.obj `if test -f 'src/ostree/ot-builtin-ls.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-ls.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-ls.c'; fi` + +src/ostree/ostree-ot-builtin-prune.o: src/ostree/ot-builtin-prune.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-prune.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Tpo -c -o src/ostree/ostree-ot-builtin-prune.o `test -f 'src/ostree/ot-builtin-prune.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-prune.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-prune.c' object='src/ostree/ostree-ot-builtin-prune.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-prune.o `test -f 'src/ostree/ot-builtin-prune.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-prune.c + +src/ostree/ostree-ot-builtin-prune.obj: src/ostree/ot-builtin-prune.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-prune.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Tpo -c -o src/ostree/ostree-ot-builtin-prune.obj `if test -f 'src/ostree/ot-builtin-prune.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-prune.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-prune.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-prune.c' object='src/ostree/ostree-ot-builtin-prune.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-prune.obj `if test -f 'src/ostree/ot-builtin-prune.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-prune.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-prune.c'; fi` + +src/ostree/ostree-ot-builtin-refs.o: src/ostree/ot-builtin-refs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-refs.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Tpo -c -o src/ostree/ostree-ot-builtin-refs.o `test -f 'src/ostree/ot-builtin-refs.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-refs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-refs.c' object='src/ostree/ostree-ot-builtin-refs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-refs.o `test -f 'src/ostree/ot-builtin-refs.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-refs.c + +src/ostree/ostree-ot-builtin-refs.obj: src/ostree/ot-builtin-refs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-refs.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Tpo -c -o src/ostree/ostree-ot-builtin-refs.obj `if test -f 'src/ostree/ot-builtin-refs.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-refs.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-refs.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-refs.c' object='src/ostree/ostree-ot-builtin-refs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-refs.obj `if test -f 'src/ostree/ot-builtin-refs.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-refs.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-refs.c'; fi` + +src/ostree/ostree-ot-builtin-remote.o: src/ostree/ot-builtin-remote.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-remote.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Tpo -c -o src/ostree/ostree-ot-builtin-remote.o `test -f 'src/ostree/ot-builtin-remote.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-remote.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-remote.c' object='src/ostree/ostree-ot-builtin-remote.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-remote.o `test -f 'src/ostree/ot-builtin-remote.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-remote.c + +src/ostree/ostree-ot-builtin-remote.obj: src/ostree/ot-builtin-remote.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-remote.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Tpo -c -o src/ostree/ostree-ot-builtin-remote.obj `if test -f 'src/ostree/ot-builtin-remote.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-remote.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-remote.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-remote.c' object='src/ostree/ostree-ot-builtin-remote.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-remote.obj `if test -f 'src/ostree/ot-builtin-remote.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-remote.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-remote.c'; fi` + +src/ostree/ostree-ot-builtin-reset.o: src/ostree/ot-builtin-reset.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-reset.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Tpo -c -o src/ostree/ostree-ot-builtin-reset.o `test -f 'src/ostree/ot-builtin-reset.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-reset.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-reset.c' object='src/ostree/ostree-ot-builtin-reset.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-reset.o `test -f 'src/ostree/ot-builtin-reset.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-reset.c + +src/ostree/ostree-ot-builtin-reset.obj: src/ostree/ot-builtin-reset.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-reset.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Tpo -c -o src/ostree/ostree-ot-builtin-reset.obj `if test -f 'src/ostree/ot-builtin-reset.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-reset.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-reset.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-reset.c' object='src/ostree/ostree-ot-builtin-reset.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-reset.obj `if test -f 'src/ostree/ot-builtin-reset.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-reset.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-reset.c'; fi` + +src/ostree/ostree-ot-builtin-rev-parse.o: src/ostree/ot-builtin-rev-parse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-rev-parse.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Tpo -c -o src/ostree/ostree-ot-builtin-rev-parse.o `test -f 'src/ostree/ot-builtin-rev-parse.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-rev-parse.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-rev-parse.c' object='src/ostree/ostree-ot-builtin-rev-parse.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-rev-parse.o `test -f 'src/ostree/ot-builtin-rev-parse.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-rev-parse.c + +src/ostree/ostree-ot-builtin-rev-parse.obj: src/ostree/ot-builtin-rev-parse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-rev-parse.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Tpo -c -o src/ostree/ostree-ot-builtin-rev-parse.obj `if test -f 'src/ostree/ot-builtin-rev-parse.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-rev-parse.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-rev-parse.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-rev-parse.c' object='src/ostree/ostree-ot-builtin-rev-parse.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-rev-parse.obj `if test -f 'src/ostree/ot-builtin-rev-parse.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-rev-parse.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-rev-parse.c'; fi` + +src/ostree/ostree-ot-builtin-sign.o: src/ostree/ot-builtin-sign.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-sign.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Tpo -c -o src/ostree/ostree-ot-builtin-sign.o `test -f 'src/ostree/ot-builtin-sign.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-sign.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-sign.c' object='src/ostree/ostree-ot-builtin-sign.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-sign.o `test -f 'src/ostree/ot-builtin-sign.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-sign.c + +src/ostree/ostree-ot-builtin-sign.obj: src/ostree/ot-builtin-sign.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-sign.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Tpo -c -o src/ostree/ostree-ot-builtin-sign.obj `if test -f 'src/ostree/ot-builtin-sign.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-sign.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-sign.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-sign.c' object='src/ostree/ostree-ot-builtin-sign.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-sign.obj `if test -f 'src/ostree/ot-builtin-sign.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-sign.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-sign.c'; fi` + +src/ostree/ostree-ot-builtin-summary.o: src/ostree/ot-builtin-summary.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-summary.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Tpo -c -o src/ostree/ostree-ot-builtin-summary.o `test -f 'src/ostree/ot-builtin-summary.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-summary.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-summary.c' object='src/ostree/ostree-ot-builtin-summary.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-summary.o `test -f 'src/ostree/ot-builtin-summary.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-summary.c + +src/ostree/ostree-ot-builtin-summary.obj: src/ostree/ot-builtin-summary.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-summary.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Tpo -c -o src/ostree/ostree-ot-builtin-summary.obj `if test -f 'src/ostree/ot-builtin-summary.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-summary.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-summary.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-summary.c' object='src/ostree/ostree-ot-builtin-summary.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-summary.obj `if test -f 'src/ostree/ot-builtin-summary.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-summary.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-summary.c'; fi` + +src/ostree/ostree-ot-builtin-show.o: src/ostree/ot-builtin-show.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-show.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Tpo -c -o src/ostree/ostree-ot-builtin-show.o `test -f 'src/ostree/ot-builtin-show.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-show.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-show.c' object='src/ostree/ostree-ot-builtin-show.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-show.o `test -f 'src/ostree/ot-builtin-show.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-show.c + +src/ostree/ostree-ot-builtin-show.obj: src/ostree/ot-builtin-show.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-show.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Tpo -c -o src/ostree/ostree-ot-builtin-show.obj `if test -f 'src/ostree/ot-builtin-show.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-show.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-show.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-show.c' object='src/ostree/ostree-ot-builtin-show.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-show.obj `if test -f 'src/ostree/ot-builtin-show.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-show.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-show.c'; fi` + +src/ostree/ostree-ot-builtin-static-delta.o: src/ostree/ot-builtin-static-delta.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-static-delta.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Tpo -c -o src/ostree/ostree-ot-builtin-static-delta.o `test -f 'src/ostree/ot-builtin-static-delta.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-static-delta.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-static-delta.c' object='src/ostree/ostree-ot-builtin-static-delta.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-static-delta.o `test -f 'src/ostree/ot-builtin-static-delta.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-static-delta.c + +src/ostree/ostree-ot-builtin-static-delta.obj: src/ostree/ot-builtin-static-delta.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-static-delta.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Tpo -c -o src/ostree/ostree-ot-builtin-static-delta.obj `if test -f 'src/ostree/ot-builtin-static-delta.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-static-delta.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-static-delta.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-static-delta.c' object='src/ostree/ostree-ot-builtin-static-delta.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-static-delta.obj `if test -f 'src/ostree/ot-builtin-static-delta.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-static-delta.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-static-delta.c'; fi` + +src/ostree/ostree-ot-main.o: src/ostree/ot-main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-main.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-main.Tpo -c -o src/ostree/ostree-ot-main.o `test -f 'src/ostree/ot-main.c' || echo '$(srcdir)/'`src/ostree/ot-main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-main.Tpo src/ostree/$(DEPDIR)/ostree-ot-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-main.c' object='src/ostree/ostree-ot-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-main.o `test -f 'src/ostree/ot-main.c' || echo '$(srcdir)/'`src/ostree/ot-main.c + +src/ostree/ostree-ot-main.obj: src/ostree/ot-main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-main.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-main.Tpo -c -o src/ostree/ostree-ot-main.obj `if test -f 'src/ostree/ot-main.c'; then $(CYGPATH_W) 'src/ostree/ot-main.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-main.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-main.Tpo src/ostree/$(DEPDIR)/ostree-ot-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-main.c' object='src/ostree/ostree-ot-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-main.obj `if test -f 'src/ostree/ot-main.c'; then $(CYGPATH_W) 'src/ostree/ot-main.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-main.c'; fi` + +src/ostree/ostree-ot-dump.o: src/ostree/ot-dump.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-dump.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-dump.Tpo -c -o src/ostree/ostree-ot-dump.o `test -f 'src/ostree/ot-dump.c' || echo '$(srcdir)/'`src/ostree/ot-dump.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-dump.Tpo src/ostree/$(DEPDIR)/ostree-ot-dump.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-dump.c' object='src/ostree/ostree-ot-dump.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-dump.o `test -f 'src/ostree/ot-dump.c' || echo '$(srcdir)/'`src/ostree/ot-dump.c + +src/ostree/ostree-ot-dump.obj: src/ostree/ot-dump.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-dump.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-dump.Tpo -c -o src/ostree/ostree-ot-dump.obj `if test -f 'src/ostree/ot-dump.c'; then $(CYGPATH_W) 'src/ostree/ot-dump.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-dump.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-dump.Tpo src/ostree/$(DEPDIR)/ostree-ot-dump.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-dump.c' object='src/ostree/ostree-ot-dump.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-dump.obj `if test -f 'src/ostree/ot-dump.c'; then $(CYGPATH_W) 'src/ostree/ot-dump.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-dump.c'; fi` + +src/ostree/ostree-ot-editor.o: src/ostree/ot-editor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-editor.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-editor.Tpo -c -o src/ostree/ostree-ot-editor.o `test -f 'src/ostree/ot-editor.c' || echo '$(srcdir)/'`src/ostree/ot-editor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-editor.Tpo src/ostree/$(DEPDIR)/ostree-ot-editor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-editor.c' object='src/ostree/ostree-ot-editor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-editor.o `test -f 'src/ostree/ot-editor.c' || echo '$(srcdir)/'`src/ostree/ot-editor.c + +src/ostree/ostree-ot-editor.obj: src/ostree/ot-editor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-editor.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-editor.Tpo -c -o src/ostree/ostree-ot-editor.obj `if test -f 'src/ostree/ot-editor.c'; then $(CYGPATH_W) 'src/ostree/ot-editor.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-editor.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-editor.Tpo src/ostree/$(DEPDIR)/ostree-ot-editor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-editor.c' object='src/ostree/ostree-ot-editor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-editor.obj `if test -f 'src/ostree/ot-editor.c'; then $(CYGPATH_W) 'src/ostree/ot-editor.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-editor.c'; fi` + +src/ostree/ostree-ot-builtin-gpg-sign.o: src/ostree/ot-builtin-gpg-sign.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-gpg-sign.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Tpo -c -o src/ostree/ostree-ot-builtin-gpg-sign.o `test -f 'src/ostree/ot-builtin-gpg-sign.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-gpg-sign.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-gpg-sign.c' object='src/ostree/ostree-ot-builtin-gpg-sign.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-gpg-sign.o `test -f 'src/ostree/ot-builtin-gpg-sign.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-gpg-sign.c + +src/ostree/ostree-ot-builtin-gpg-sign.obj: src/ostree/ot-builtin-gpg-sign.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-gpg-sign.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Tpo -c -o src/ostree/ostree-ot-builtin-gpg-sign.obj `if test -f 'src/ostree/ot-builtin-gpg-sign.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-gpg-sign.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-gpg-sign.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-gpg-sign.c' object='src/ostree/ostree-ot-builtin-gpg-sign.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-gpg-sign.obj `if test -f 'src/ostree/ot-builtin-gpg-sign.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-gpg-sign.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-gpg-sign.c'; fi` + +src/ostree/ostree-ot-admin-builtin-init-fs.o: src/ostree/ot-admin-builtin-init-fs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-init-fs.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Tpo -c -o src/ostree/ostree-ot-admin-builtin-init-fs.o `test -f 'src/ostree/ot-admin-builtin-init-fs.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-init-fs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-init-fs.c' object='src/ostree/ostree-ot-admin-builtin-init-fs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-init-fs.o `test -f 'src/ostree/ot-admin-builtin-init-fs.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-init-fs.c + +src/ostree/ostree-ot-admin-builtin-init-fs.obj: src/ostree/ot-admin-builtin-init-fs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-init-fs.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Tpo -c -o src/ostree/ostree-ot-admin-builtin-init-fs.obj `if test -f 'src/ostree/ot-admin-builtin-init-fs.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-init-fs.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-init-fs.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-init-fs.c' object='src/ostree/ostree-ot-admin-builtin-init-fs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-init-fs.obj `if test -f 'src/ostree/ot-admin-builtin-init-fs.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-init-fs.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-init-fs.c'; fi` + +src/ostree/ostree-ot-admin-builtin-diff.o: src/ostree/ot-admin-builtin-diff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-diff.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Tpo -c -o src/ostree/ostree-ot-admin-builtin-diff.o `test -f 'src/ostree/ot-admin-builtin-diff.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-diff.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-diff.c' object='src/ostree/ostree-ot-admin-builtin-diff.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-diff.o `test -f 'src/ostree/ot-admin-builtin-diff.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-diff.c + +src/ostree/ostree-ot-admin-builtin-diff.obj: src/ostree/ot-admin-builtin-diff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-diff.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Tpo -c -o src/ostree/ostree-ot-admin-builtin-diff.obj `if test -f 'src/ostree/ot-admin-builtin-diff.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-diff.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-diff.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-diff.c' object='src/ostree/ostree-ot-admin-builtin-diff.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-diff.obj `if test -f 'src/ostree/ot-admin-builtin-diff.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-diff.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-diff.c'; fi` + +src/ostree/ostree-ot-admin-builtin-deploy.o: src/ostree/ot-admin-builtin-deploy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-deploy.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Tpo -c -o src/ostree/ostree-ot-admin-builtin-deploy.o `test -f 'src/ostree/ot-admin-builtin-deploy.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-deploy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-deploy.c' object='src/ostree/ostree-ot-admin-builtin-deploy.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-deploy.o `test -f 'src/ostree/ot-admin-builtin-deploy.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-deploy.c + +src/ostree/ostree-ot-admin-builtin-deploy.obj: src/ostree/ot-admin-builtin-deploy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-deploy.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Tpo -c -o src/ostree/ostree-ot-admin-builtin-deploy.obj `if test -f 'src/ostree/ot-admin-builtin-deploy.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-deploy.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-deploy.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-deploy.c' object='src/ostree/ostree-ot-admin-builtin-deploy.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-deploy.obj `if test -f 'src/ostree/ot-admin-builtin-deploy.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-deploy.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-deploy.c'; fi` + +src/ostree/ostree-ot-admin-builtin-finalize-staged.o: src/ostree/ot-admin-builtin-finalize-staged.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-finalize-staged.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Tpo -c -o src/ostree/ostree-ot-admin-builtin-finalize-staged.o `test -f 'src/ostree/ot-admin-builtin-finalize-staged.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-finalize-staged.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-finalize-staged.c' object='src/ostree/ostree-ot-admin-builtin-finalize-staged.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-finalize-staged.o `test -f 'src/ostree/ot-admin-builtin-finalize-staged.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-finalize-staged.c + +src/ostree/ostree-ot-admin-builtin-finalize-staged.obj: src/ostree/ot-admin-builtin-finalize-staged.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-finalize-staged.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Tpo -c -o src/ostree/ostree-ot-admin-builtin-finalize-staged.obj `if test -f 'src/ostree/ot-admin-builtin-finalize-staged.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-finalize-staged.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-finalize-staged.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-finalize-staged.c' object='src/ostree/ostree-ot-admin-builtin-finalize-staged.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-finalize-staged.obj `if test -f 'src/ostree/ot-admin-builtin-finalize-staged.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-finalize-staged.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-finalize-staged.c'; fi` + +src/ostree/ostree-ot-admin-builtin-undeploy.o: src/ostree/ot-admin-builtin-undeploy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-undeploy.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Tpo -c -o src/ostree/ostree-ot-admin-builtin-undeploy.o `test -f 'src/ostree/ot-admin-builtin-undeploy.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-undeploy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-undeploy.c' object='src/ostree/ostree-ot-admin-builtin-undeploy.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-undeploy.o `test -f 'src/ostree/ot-admin-builtin-undeploy.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-undeploy.c + +src/ostree/ostree-ot-admin-builtin-undeploy.obj: src/ostree/ot-admin-builtin-undeploy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-undeploy.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Tpo -c -o src/ostree/ostree-ot-admin-builtin-undeploy.obj `if test -f 'src/ostree/ot-admin-builtin-undeploy.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-undeploy.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-undeploy.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-undeploy.c' object='src/ostree/ostree-ot-admin-builtin-undeploy.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-undeploy.obj `if test -f 'src/ostree/ot-admin-builtin-undeploy.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-undeploy.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-undeploy.c'; fi` + +src/ostree/ostree-ot-admin-builtin-instutil.o: src/ostree/ot-admin-builtin-instutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-instutil.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Tpo -c -o src/ostree/ostree-ot-admin-builtin-instutil.o `test -f 'src/ostree/ot-admin-builtin-instutil.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-instutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-instutil.c' object='src/ostree/ostree-ot-admin-builtin-instutil.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-instutil.o `test -f 'src/ostree/ot-admin-builtin-instutil.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-instutil.c + +src/ostree/ostree-ot-admin-builtin-instutil.obj: src/ostree/ot-admin-builtin-instutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-instutil.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Tpo -c -o src/ostree/ostree-ot-admin-builtin-instutil.obj `if test -f 'src/ostree/ot-admin-builtin-instutil.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-instutil.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-instutil.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-instutil.c' object='src/ostree/ostree-ot-admin-builtin-instutil.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-instutil.obj `if test -f 'src/ostree/ot-admin-builtin-instutil.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-instutil.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-instutil.c'; fi` + +src/ostree/ostree-ot-admin-builtin-cleanup.o: src/ostree/ot-admin-builtin-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-cleanup.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Tpo -c -o src/ostree/ostree-ot-admin-builtin-cleanup.o `test -f 'src/ostree/ot-admin-builtin-cleanup.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-cleanup.c' object='src/ostree/ostree-ot-admin-builtin-cleanup.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-cleanup.o `test -f 'src/ostree/ot-admin-builtin-cleanup.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-cleanup.c + +src/ostree/ostree-ot-admin-builtin-cleanup.obj: src/ostree/ot-admin-builtin-cleanup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-cleanup.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Tpo -c -o src/ostree/ostree-ot-admin-builtin-cleanup.obj `if test -f 'src/ostree/ot-admin-builtin-cleanup.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-cleanup.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-cleanup.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-cleanup.c' object='src/ostree/ostree-ot-admin-builtin-cleanup.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-cleanup.obj `if test -f 'src/ostree/ot-admin-builtin-cleanup.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-cleanup.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-cleanup.c'; fi` + +src/ostree/ostree-ot-admin-builtin-os-init.o: src/ostree/ot-admin-builtin-os-init.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-os-init.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Tpo -c -o src/ostree/ostree-ot-admin-builtin-os-init.o `test -f 'src/ostree/ot-admin-builtin-os-init.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-os-init.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-os-init.c' object='src/ostree/ostree-ot-admin-builtin-os-init.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-os-init.o `test -f 'src/ostree/ot-admin-builtin-os-init.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-os-init.c + +src/ostree/ostree-ot-admin-builtin-os-init.obj: src/ostree/ot-admin-builtin-os-init.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-os-init.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Tpo -c -o src/ostree/ostree-ot-admin-builtin-os-init.obj `if test -f 'src/ostree/ot-admin-builtin-os-init.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-os-init.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-os-init.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-os-init.c' object='src/ostree/ostree-ot-admin-builtin-os-init.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-os-init.obj `if test -f 'src/ostree/ot-admin-builtin-os-init.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-os-init.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-os-init.c'; fi` + +src/ostree/ostree-ot-admin-builtin-set-origin.o: src/ostree/ot-admin-builtin-set-origin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-set-origin.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Tpo -c -o src/ostree/ostree-ot-admin-builtin-set-origin.o `test -f 'src/ostree/ot-admin-builtin-set-origin.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-set-origin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-set-origin.c' object='src/ostree/ostree-ot-admin-builtin-set-origin.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-set-origin.o `test -f 'src/ostree/ot-admin-builtin-set-origin.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-set-origin.c + +src/ostree/ostree-ot-admin-builtin-set-origin.obj: src/ostree/ot-admin-builtin-set-origin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-set-origin.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Tpo -c -o src/ostree/ostree-ot-admin-builtin-set-origin.obj `if test -f 'src/ostree/ot-admin-builtin-set-origin.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-set-origin.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-set-origin.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-set-origin.c' object='src/ostree/ostree-ot-admin-builtin-set-origin.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-set-origin.obj `if test -f 'src/ostree/ot-admin-builtin-set-origin.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-set-origin.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-set-origin.c'; fi` + +src/ostree/ostree-ot-admin-builtin-status.o: src/ostree/ot-admin-builtin-status.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-status.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Tpo -c -o src/ostree/ostree-ot-admin-builtin-status.o `test -f 'src/ostree/ot-admin-builtin-status.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-status.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-status.c' object='src/ostree/ostree-ot-admin-builtin-status.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-status.o `test -f 'src/ostree/ot-admin-builtin-status.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-status.c + +src/ostree/ostree-ot-admin-builtin-status.obj: src/ostree/ot-admin-builtin-status.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-status.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Tpo -c -o src/ostree/ostree-ot-admin-builtin-status.obj `if test -f 'src/ostree/ot-admin-builtin-status.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-status.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-status.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-status.c' object='src/ostree/ostree-ot-admin-builtin-status.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-status.obj `if test -f 'src/ostree/ot-admin-builtin-status.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-status.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-status.c'; fi` + +src/ostree/ostree-ot-admin-builtin-switch.o: src/ostree/ot-admin-builtin-switch.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-switch.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Tpo -c -o src/ostree/ostree-ot-admin-builtin-switch.o `test -f 'src/ostree/ot-admin-builtin-switch.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-switch.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-switch.c' object='src/ostree/ostree-ot-admin-builtin-switch.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-switch.o `test -f 'src/ostree/ot-admin-builtin-switch.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-switch.c + +src/ostree/ostree-ot-admin-builtin-switch.obj: src/ostree/ot-admin-builtin-switch.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-switch.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Tpo -c -o src/ostree/ostree-ot-admin-builtin-switch.obj `if test -f 'src/ostree/ot-admin-builtin-switch.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-switch.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-switch.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-switch.c' object='src/ostree/ostree-ot-admin-builtin-switch.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-switch.obj `if test -f 'src/ostree/ot-admin-builtin-switch.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-switch.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-switch.c'; fi` + +src/ostree/ostree-ot-admin-builtin-pin.o: src/ostree/ot-admin-builtin-pin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-pin.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Tpo -c -o src/ostree/ostree-ot-admin-builtin-pin.o `test -f 'src/ostree/ot-admin-builtin-pin.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-pin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-pin.c' object='src/ostree/ostree-ot-admin-builtin-pin.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-pin.o `test -f 'src/ostree/ot-admin-builtin-pin.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-pin.c + +src/ostree/ostree-ot-admin-builtin-pin.obj: src/ostree/ot-admin-builtin-pin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-pin.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Tpo -c -o src/ostree/ostree-ot-admin-builtin-pin.obj `if test -f 'src/ostree/ot-admin-builtin-pin.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-pin.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-pin.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-pin.c' object='src/ostree/ostree-ot-admin-builtin-pin.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-pin.obj `if test -f 'src/ostree/ot-admin-builtin-pin.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-pin.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-pin.c'; fi` + +src/ostree/ostree-ot-admin-builtin-upgrade.o: src/ostree/ot-admin-builtin-upgrade.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-upgrade.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Tpo -c -o src/ostree/ostree-ot-admin-builtin-upgrade.o `test -f 'src/ostree/ot-admin-builtin-upgrade.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-upgrade.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-upgrade.c' object='src/ostree/ostree-ot-admin-builtin-upgrade.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-upgrade.o `test -f 'src/ostree/ot-admin-builtin-upgrade.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-upgrade.c + +src/ostree/ostree-ot-admin-builtin-upgrade.obj: src/ostree/ot-admin-builtin-upgrade.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-upgrade.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Tpo -c -o src/ostree/ostree-ot-admin-builtin-upgrade.obj `if test -f 'src/ostree/ot-admin-builtin-upgrade.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-upgrade.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-upgrade.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-upgrade.c' object='src/ostree/ostree-ot-admin-builtin-upgrade.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-upgrade.obj `if test -f 'src/ostree/ot-admin-builtin-upgrade.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-upgrade.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-upgrade.c'; fi` + +src/ostree/ostree-ot-admin-builtin-unlock.o: src/ostree/ot-admin-builtin-unlock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-unlock.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Tpo -c -o src/ostree/ostree-ot-admin-builtin-unlock.o `test -f 'src/ostree/ot-admin-builtin-unlock.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-unlock.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-unlock.c' object='src/ostree/ostree-ot-admin-builtin-unlock.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-unlock.o `test -f 'src/ostree/ot-admin-builtin-unlock.c' || echo '$(srcdir)/'`src/ostree/ot-admin-builtin-unlock.c + +src/ostree/ostree-ot-admin-builtin-unlock.obj: src/ostree/ot-admin-builtin-unlock.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-builtin-unlock.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Tpo -c -o src/ostree/ostree-ot-admin-builtin-unlock.obj `if test -f 'src/ostree/ot-admin-builtin-unlock.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-unlock.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-unlock.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-builtin-unlock.c' object='src/ostree/ostree-ot-admin-builtin-unlock.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-builtin-unlock.obj `if test -f 'src/ostree/ot-admin-builtin-unlock.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-builtin-unlock.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-builtin-unlock.c'; fi` + +src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.o: src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Tpo -c -o src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.o `test -f 'src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c' || echo '$(srcdir)/'`src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c' object='src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.o `test -f 'src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c' || echo '$(srcdir)/'`src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c + +src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.obj: src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Tpo -c -o src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.obj `if test -f 'src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c' object='src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.obj `if test -f 'src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c'; fi` + +src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.o: src/ostree/ot-admin-instutil-builtin-set-kargs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Tpo -c -o src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.o `test -f 'src/ostree/ot-admin-instutil-builtin-set-kargs.c' || echo '$(srcdir)/'`src/ostree/ot-admin-instutil-builtin-set-kargs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-instutil-builtin-set-kargs.c' object='src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.o `test -f 'src/ostree/ot-admin-instutil-builtin-set-kargs.c' || echo '$(srcdir)/'`src/ostree/ot-admin-instutil-builtin-set-kargs.c + +src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.obj: src/ostree/ot-admin-instutil-builtin-set-kargs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Tpo -c -o src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.obj `if test -f 'src/ostree/ot-admin-instutil-builtin-set-kargs.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-instutil-builtin-set-kargs.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-instutil-builtin-set-kargs.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-instutil-builtin-set-kargs.c' object='src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-instutil-builtin-set-kargs.obj `if test -f 'src/ostree/ot-admin-instutil-builtin-set-kargs.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-instutil-builtin-set-kargs.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-instutil-builtin-set-kargs.c'; fi` + +src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.o: src/ostree/ot-admin-instutil-builtin-grub2-generate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Tpo -c -o src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.o `test -f 'src/ostree/ot-admin-instutil-builtin-grub2-generate.c' || echo '$(srcdir)/'`src/ostree/ot-admin-instutil-builtin-grub2-generate.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-instutil-builtin-grub2-generate.c' object='src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.o `test -f 'src/ostree/ot-admin-instutil-builtin-grub2-generate.c' || echo '$(srcdir)/'`src/ostree/ot-admin-instutil-builtin-grub2-generate.c + +src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.obj: src/ostree/ot-admin-instutil-builtin-grub2-generate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Tpo -c -o src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.obj `if test -f 'src/ostree/ot-admin-instutil-builtin-grub2-generate.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-instutil-builtin-grub2-generate.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-instutil-builtin-grub2-generate.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-instutil-builtin-grub2-generate.c' object='src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-instutil-builtin-grub2-generate.obj `if test -f 'src/ostree/ot-admin-instutil-builtin-grub2-generate.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-instutil-builtin-grub2-generate.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-instutil-builtin-grub2-generate.c'; fi` + +src/ostree/ostree-ot-admin-functions.o: src/ostree/ot-admin-functions.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-functions.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Tpo -c -o src/ostree/ostree-ot-admin-functions.o `test -f 'src/ostree/ot-admin-functions.c' || echo '$(srcdir)/'`src/ostree/ot-admin-functions.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-functions.c' object='src/ostree/ostree-ot-admin-functions.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-functions.o `test -f 'src/ostree/ot-admin-functions.c' || echo '$(srcdir)/'`src/ostree/ot-admin-functions.c + +src/ostree/ostree-ot-admin-functions.obj: src/ostree/ot-admin-functions.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-admin-functions.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Tpo -c -o src/ostree/ostree-ot-admin-functions.obj `if test -f 'src/ostree/ot-admin-functions.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-functions.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-functions.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Tpo src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-admin-functions.c' object='src/ostree/ostree-ot-admin-functions.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-admin-functions.obj `if test -f 'src/ostree/ot-admin-functions.c'; then $(CYGPATH_W) 'src/ostree/ot-admin-functions.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-admin-functions.c'; fi` + +src/ostree/ostree-ot-remote-builtin-add.o: src/ostree/ot-remote-builtin-add.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-add.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Tpo -c -o src/ostree/ostree-ot-remote-builtin-add.o `test -f 'src/ostree/ot-remote-builtin-add.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-add.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-add.c' object='src/ostree/ostree-ot-remote-builtin-add.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-add.o `test -f 'src/ostree/ot-remote-builtin-add.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-add.c + +src/ostree/ostree-ot-remote-builtin-add.obj: src/ostree/ot-remote-builtin-add.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-add.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Tpo -c -o src/ostree/ostree-ot-remote-builtin-add.obj `if test -f 'src/ostree/ot-remote-builtin-add.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-add.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-add.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-add.c' object='src/ostree/ostree-ot-remote-builtin-add.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-add.obj `if test -f 'src/ostree/ot-remote-builtin-add.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-add.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-add.c'; fi` + +src/ostree/ostree-ot-remote-builtin-delete.o: src/ostree/ot-remote-builtin-delete.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-delete.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Tpo -c -o src/ostree/ostree-ot-remote-builtin-delete.o `test -f 'src/ostree/ot-remote-builtin-delete.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-delete.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-delete.c' object='src/ostree/ostree-ot-remote-builtin-delete.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-delete.o `test -f 'src/ostree/ot-remote-builtin-delete.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-delete.c + +src/ostree/ostree-ot-remote-builtin-delete.obj: src/ostree/ot-remote-builtin-delete.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-delete.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Tpo -c -o src/ostree/ostree-ot-remote-builtin-delete.obj `if test -f 'src/ostree/ot-remote-builtin-delete.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-delete.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-delete.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-delete.c' object='src/ostree/ostree-ot-remote-builtin-delete.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-delete.obj `if test -f 'src/ostree/ot-remote-builtin-delete.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-delete.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-delete.c'; fi` + +src/ostree/ostree-ot-remote-builtin-list.o: src/ostree/ot-remote-builtin-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-list.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Tpo -c -o src/ostree/ostree-ot-remote-builtin-list.o `test -f 'src/ostree/ot-remote-builtin-list.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-list.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-list.c' object='src/ostree/ostree-ot-remote-builtin-list.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-list.o `test -f 'src/ostree/ot-remote-builtin-list.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-list.c + +src/ostree/ostree-ot-remote-builtin-list.obj: src/ostree/ot-remote-builtin-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-list.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Tpo -c -o src/ostree/ostree-ot-remote-builtin-list.obj `if test -f 'src/ostree/ot-remote-builtin-list.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-list.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-list.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-list.c' object='src/ostree/ostree-ot-remote-builtin-list.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-list.obj `if test -f 'src/ostree/ot-remote-builtin-list.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-list.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-list.c'; fi` + +src/ostree/ostree-ot-remote-builtin-show-url.o: src/ostree/ot-remote-builtin-show-url.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-show-url.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Tpo -c -o src/ostree/ostree-ot-remote-builtin-show-url.o `test -f 'src/ostree/ot-remote-builtin-show-url.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-show-url.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-show-url.c' object='src/ostree/ostree-ot-remote-builtin-show-url.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-show-url.o `test -f 'src/ostree/ot-remote-builtin-show-url.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-show-url.c + +src/ostree/ostree-ot-remote-builtin-show-url.obj: src/ostree/ot-remote-builtin-show-url.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-show-url.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Tpo -c -o src/ostree/ostree-ot-remote-builtin-show-url.obj `if test -f 'src/ostree/ot-remote-builtin-show-url.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-show-url.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-show-url.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-show-url.c' object='src/ostree/ostree-ot-remote-builtin-show-url.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-show-url.obj `if test -f 'src/ostree/ot-remote-builtin-show-url.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-show-url.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-show-url.c'; fi` + +src/ostree/ostree-ot-remote-builtin-refs.o: src/ostree/ot-remote-builtin-refs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-refs.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Tpo -c -o src/ostree/ostree-ot-remote-builtin-refs.o `test -f 'src/ostree/ot-remote-builtin-refs.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-refs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-refs.c' object='src/ostree/ostree-ot-remote-builtin-refs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-refs.o `test -f 'src/ostree/ot-remote-builtin-refs.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-refs.c + +src/ostree/ostree-ot-remote-builtin-refs.obj: src/ostree/ot-remote-builtin-refs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-refs.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Tpo -c -o src/ostree/ostree-ot-remote-builtin-refs.obj `if test -f 'src/ostree/ot-remote-builtin-refs.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-refs.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-refs.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-refs.c' object='src/ostree/ostree-ot-remote-builtin-refs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-refs.obj `if test -f 'src/ostree/ot-remote-builtin-refs.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-refs.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-refs.c'; fi` + +src/ostree/ostree-ot-remote-builtin-summary.o: src/ostree/ot-remote-builtin-summary.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-summary.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Tpo -c -o src/ostree/ostree-ot-remote-builtin-summary.o `test -f 'src/ostree/ot-remote-builtin-summary.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-summary.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-summary.c' object='src/ostree/ostree-ot-remote-builtin-summary.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-summary.o `test -f 'src/ostree/ot-remote-builtin-summary.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-summary.c + +src/ostree/ostree-ot-remote-builtin-summary.obj: src/ostree/ot-remote-builtin-summary.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-summary.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Tpo -c -o src/ostree/ostree-ot-remote-builtin-summary.obj `if test -f 'src/ostree/ot-remote-builtin-summary.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-summary.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-summary.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-summary.c' object='src/ostree/ostree-ot-remote-builtin-summary.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-summary.obj `if test -f 'src/ostree/ot-remote-builtin-summary.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-summary.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-summary.c'; fi` + +src/ostree/ostree-ot-remote-builtin-gpg-import.o: src/ostree/ot-remote-builtin-gpg-import.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-gpg-import.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Tpo -c -o src/ostree/ostree-ot-remote-builtin-gpg-import.o `test -f 'src/ostree/ot-remote-builtin-gpg-import.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-gpg-import.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-gpg-import.c' object='src/ostree/ostree-ot-remote-builtin-gpg-import.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-gpg-import.o `test -f 'src/ostree/ot-remote-builtin-gpg-import.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-gpg-import.c + +src/ostree/ostree-ot-remote-builtin-gpg-import.obj: src/ostree/ot-remote-builtin-gpg-import.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-gpg-import.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Tpo -c -o src/ostree/ostree-ot-remote-builtin-gpg-import.obj `if test -f 'src/ostree/ot-remote-builtin-gpg-import.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-gpg-import.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-gpg-import.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-gpg-import.c' object='src/ostree/ostree-ot-remote-builtin-gpg-import.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-gpg-import.obj `if test -f 'src/ostree/ot-remote-builtin-gpg-import.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-gpg-import.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-gpg-import.c'; fi` + +src/ostree/ostree-ot-remote-builtin-add-cookie.o: src/ostree/ot-remote-builtin-add-cookie.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-add-cookie.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Tpo -c -o src/ostree/ostree-ot-remote-builtin-add-cookie.o `test -f 'src/ostree/ot-remote-builtin-add-cookie.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-add-cookie.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-add-cookie.c' object='src/ostree/ostree-ot-remote-builtin-add-cookie.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-add-cookie.o `test -f 'src/ostree/ot-remote-builtin-add-cookie.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-add-cookie.c + +src/ostree/ostree-ot-remote-builtin-add-cookie.obj: src/ostree/ot-remote-builtin-add-cookie.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-add-cookie.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Tpo -c -o src/ostree/ostree-ot-remote-builtin-add-cookie.obj `if test -f 'src/ostree/ot-remote-builtin-add-cookie.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-add-cookie.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-add-cookie.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-add-cookie.c' object='src/ostree/ostree-ot-remote-builtin-add-cookie.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-add-cookie.obj `if test -f 'src/ostree/ot-remote-builtin-add-cookie.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-add-cookie.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-add-cookie.c'; fi` + +src/ostree/ostree-ot-remote-builtin-delete-cookie.o: src/ostree/ot-remote-builtin-delete-cookie.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-delete-cookie.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Tpo -c -o src/ostree/ostree-ot-remote-builtin-delete-cookie.o `test -f 'src/ostree/ot-remote-builtin-delete-cookie.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-delete-cookie.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-delete-cookie.c' object='src/ostree/ostree-ot-remote-builtin-delete-cookie.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-delete-cookie.o `test -f 'src/ostree/ot-remote-builtin-delete-cookie.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-delete-cookie.c + +src/ostree/ostree-ot-remote-builtin-delete-cookie.obj: src/ostree/ot-remote-builtin-delete-cookie.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-delete-cookie.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Tpo -c -o src/ostree/ostree-ot-remote-builtin-delete-cookie.obj `if test -f 'src/ostree/ot-remote-builtin-delete-cookie.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-delete-cookie.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-delete-cookie.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-delete-cookie.c' object='src/ostree/ostree-ot-remote-builtin-delete-cookie.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-delete-cookie.obj `if test -f 'src/ostree/ot-remote-builtin-delete-cookie.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-delete-cookie.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-delete-cookie.c'; fi` + +src/ostree/ostree-ot-remote-builtin-list-cookies.o: src/ostree/ot-remote-builtin-list-cookies.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-list-cookies.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Tpo -c -o src/ostree/ostree-ot-remote-builtin-list-cookies.o `test -f 'src/ostree/ot-remote-builtin-list-cookies.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-list-cookies.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-list-cookies.c' object='src/ostree/ostree-ot-remote-builtin-list-cookies.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-list-cookies.o `test -f 'src/ostree/ot-remote-builtin-list-cookies.c' || echo '$(srcdir)/'`src/ostree/ot-remote-builtin-list-cookies.c + +src/ostree/ostree-ot-remote-builtin-list-cookies.obj: src/ostree/ot-remote-builtin-list-cookies.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-builtin-list-cookies.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Tpo -c -o src/ostree/ostree-ot-remote-builtin-list-cookies.obj `if test -f 'src/ostree/ot-remote-builtin-list-cookies.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-list-cookies.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-list-cookies.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-builtin-list-cookies.c' object='src/ostree/ostree-ot-remote-builtin-list-cookies.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-builtin-list-cookies.obj `if test -f 'src/ostree/ot-remote-builtin-list-cookies.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-builtin-list-cookies.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-builtin-list-cookies.c'; fi` + +src/ostree/ostree-ot-remote-cookie-util.o: src/ostree/ot-remote-cookie-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-cookie-util.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Tpo -c -o src/ostree/ostree-ot-remote-cookie-util.o `test -f 'src/ostree/ot-remote-cookie-util.c' || echo '$(srcdir)/'`src/ostree/ot-remote-cookie-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-cookie-util.c' object='src/ostree/ostree-ot-remote-cookie-util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-cookie-util.o `test -f 'src/ostree/ot-remote-cookie-util.c' || echo '$(srcdir)/'`src/ostree/ot-remote-cookie-util.c + +src/ostree/ostree-ot-remote-cookie-util.obj: src/ostree/ot-remote-cookie-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-remote-cookie-util.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Tpo -c -o src/ostree/ostree-ot-remote-cookie-util.obj `if test -f 'src/ostree/ot-remote-cookie-util.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-cookie-util.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-cookie-util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Tpo src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-remote-cookie-util.c' object='src/ostree/ostree-ot-remote-cookie-util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-remote-cookie-util.obj `if test -f 'src/ostree/ot-remote-cookie-util.c'; then $(CYGPATH_W) 'src/ostree/ot-remote-cookie-util.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-remote-cookie-util.c'; fi` + +src/ostree/ostree-ot-builtin-pull.o: src/ostree/ot-builtin-pull.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-pull.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Tpo -c -o src/ostree/ostree-ot-builtin-pull.o `test -f 'src/ostree/ot-builtin-pull.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-pull.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-pull.c' object='src/ostree/ostree-ot-builtin-pull.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-pull.o `test -f 'src/ostree/ot-builtin-pull.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-pull.c + +src/ostree/ostree-ot-builtin-pull.obj: src/ostree/ot-builtin-pull.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-pull.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Tpo -c -o src/ostree/ostree-ot-builtin-pull.obj `if test -f 'src/ostree/ot-builtin-pull.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-pull.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-pull.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-pull.c' object='src/ostree/ostree-ot-builtin-pull.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-pull.obj `if test -f 'src/ostree/ot-builtin-pull.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-pull.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-pull.c'; fi` + +src/ostree/ostree-ot-builtin-trivial-httpd.o: src/ostree/ot-builtin-trivial-httpd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-trivial-httpd.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Tpo -c -o src/ostree/ostree-ot-builtin-trivial-httpd.o `test -f 'src/ostree/ot-builtin-trivial-httpd.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-trivial-httpd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-trivial-httpd.c' object='src/ostree/ostree-ot-builtin-trivial-httpd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-trivial-httpd.o `test -f 'src/ostree/ot-builtin-trivial-httpd.c' || echo '$(srcdir)/'`src/ostree/ot-builtin-trivial-httpd.c + +src/ostree/ostree-ot-builtin-trivial-httpd.obj: src/ostree/ot-builtin-trivial-httpd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-ot-builtin-trivial-httpd.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Tpo -c -o src/ostree/ostree-ot-builtin-trivial-httpd.obj `if test -f 'src/ostree/ot-builtin-trivial-httpd.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-trivial-httpd.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-trivial-httpd.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Tpo src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ot-builtin-trivial-httpd.c' object='src/ostree/ostree-ot-builtin-trivial-httpd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-trivial-httpd.obj `if test -f 'src/ostree/ot-builtin-trivial-httpd.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-trivial-httpd.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-trivial-httpd.c'; fi` + +src/ostree/ostree-parse-datetime.o: src/ostree/parse-datetime.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-parse-datetime.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree-parse-datetime.Tpo -c -o src/ostree/ostree-parse-datetime.o `test -f 'src/ostree/parse-datetime.c' || echo '$(srcdir)/'`src/ostree/parse-datetime.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-parse-datetime.Tpo src/ostree/$(DEPDIR)/ostree-parse-datetime.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/parse-datetime.c' object='src/ostree/ostree-parse-datetime.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-parse-datetime.o `test -f 'src/ostree/parse-datetime.c' || echo '$(srcdir)/'`src/ostree/parse-datetime.c + +src/ostree/ostree-parse-datetime.obj: src/ostree/parse-datetime.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -MT src/ostree/ostree-parse-datetime.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree-parse-datetime.Tpo -c -o src/ostree/ostree-parse-datetime.obj `if test -f 'src/ostree/parse-datetime.c'; then $(CYGPATH_W) 'src/ostree/parse-datetime.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/parse-datetime.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree-parse-datetime.Tpo src/ostree/$(DEPDIR)/ostree-parse-datetime.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/parse-datetime.c' object='src/ostree/ostree-parse-datetime.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-parse-datetime.obj `if test -f 'src/ostree/parse-datetime.c'; then $(CYGPATH_W) 'src/ostree/parse-datetime.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/parse-datetime.c'; fi` + +src/switchroot/ostree_prepare_root-ostree-prepare-root.o: src/switchroot/ostree-prepare-root.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_prepare_root_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_prepare_root-ostree-prepare-root.o -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.o `test -f 'src/switchroot/ostree-prepare-root.c' || echo '$(srcdir)/'`src/switchroot/ostree-prepare-root.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-prepare-root.c' object='src/switchroot/ostree_prepare_root-ostree-prepare-root.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_prepare_root_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.o `test -f 'src/switchroot/ostree-prepare-root.c' || echo '$(srcdir)/'`src/switchroot/ostree-prepare-root.c + +src/switchroot/ostree_prepare_root-ostree-prepare-root.obj: src/switchroot/ostree-prepare-root.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_prepare_root_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_prepare_root-ostree-prepare-root.obj -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.obj `if test -f 'src/switchroot/ostree-prepare-root.c'; then $(CYGPATH_W) 'src/switchroot/ostree-prepare-root.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-prepare-root.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-prepare-root.c' object='src/switchroot/ostree_prepare_root-ostree-prepare-root.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_prepare_root_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.obj `if test -f 'src/switchroot/ostree-prepare-root.c'; then $(CYGPATH_W) 'src/switchroot/ostree-prepare-root.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-prepare-root.c'; fi` + +src/switchroot/ostree_remount-ostree-remount.o: src/switchroot/ostree-remount.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_remount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_remount-ostree-remount.o -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo -c -o src/switchroot/ostree_remount-ostree-remount.o `test -f 'src/switchroot/ostree-remount.c' || echo '$(srcdir)/'`src/switchroot/ostree-remount.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-remount.c' object='src/switchroot/ostree_remount-ostree-remount.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_remount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_remount-ostree-remount.o `test -f 'src/switchroot/ostree-remount.c' || echo '$(srcdir)/'`src/switchroot/ostree-remount.c + +src/switchroot/ostree_remount-ostree-remount.obj: src/switchroot/ostree-remount.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_remount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_remount-ostree-remount.obj -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo -c -o src/switchroot/ostree_remount-ostree-remount.obj `if test -f 'src/switchroot/ostree-remount.c'; then $(CYGPATH_W) 'src/switchroot/ostree-remount.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-remount.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-remount.c' object='src/switchroot/ostree_remount-ostree-remount.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_remount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_remount-ostree-remount.obj `if test -f 'src/switchroot/ostree-remount.c'; then $(CYGPATH_W) 'src/switchroot/ostree-remount.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-remount.c'; fi` + +src/switchroot/ostree_system_generator-ostree-system-generator.o: src/switchroot/ostree-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_system_generator_CPPFLAGS) $(CPPFLAGS) $(ostree_system_generator_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_system_generator-ostree-system-generator.o -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Tpo -c -o src/switchroot/ostree_system_generator-ostree-system-generator.o `test -f 'src/switchroot/ostree-system-generator.c' || echo '$(srcdir)/'`src/switchroot/ostree-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Tpo src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-system-generator.c' object='src/switchroot/ostree_system_generator-ostree-system-generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_system_generator_CPPFLAGS) $(CPPFLAGS) $(ostree_system_generator_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_system_generator-ostree-system-generator.o `test -f 'src/switchroot/ostree-system-generator.c' || echo '$(srcdir)/'`src/switchroot/ostree-system-generator.c + +src/switchroot/ostree_system_generator-ostree-system-generator.obj: src/switchroot/ostree-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_system_generator_CPPFLAGS) $(CPPFLAGS) $(ostree_system_generator_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_system_generator-ostree-system-generator.obj -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Tpo -c -o src/switchroot/ostree_system_generator-ostree-system-generator.obj `if test -f 'src/switchroot/ostree-system-generator.c'; then $(CYGPATH_W) 'src/switchroot/ostree-system-generator.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-system-generator.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Tpo src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-system-generator.c' object='src/switchroot/ostree_system_generator-ostree-system-generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_system_generator_CPPFLAGS) $(CPPFLAGS) $(ostree_system_generator_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_system_generator-ostree-system-generator.obj `if test -f 'src/switchroot/ostree-system-generator.c'; then $(CYGPATH_W) 'src/switchroot/ostree-system-generator.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-system-generator.c'; fi` + +src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.o: src/ostree/ostree-trivial-httpd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_trivial_httpd_CFLAGS) $(CFLAGS) -MT src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Tpo -c -o src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.o `test -f 'src/ostree/ostree-trivial-httpd.c' || echo '$(srcdir)/'`src/ostree/ostree-trivial-httpd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Tpo src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ostree-trivial-httpd.c' object='src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_trivial_httpd_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.o `test -f 'src/ostree/ostree-trivial-httpd.c' || echo '$(srcdir)/'`src/ostree/ostree-trivial-httpd.c + +src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.obj: src/ostree/ostree-trivial-httpd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_trivial_httpd_CFLAGS) $(CFLAGS) -MT src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.obj -MD -MP -MF src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Tpo -c -o src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.obj `if test -f 'src/ostree/ostree-trivial-httpd.c'; then $(CYGPATH_W) 'src/ostree/ostree-trivial-httpd.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ostree-trivial-httpd.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Tpo src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/ostree/ostree-trivial-httpd.c' object='src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_trivial_httpd_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.obj `if test -f 'src/ostree/ostree-trivial-httpd.c'; then $(CYGPATH_W) 'src/ostree/ostree-trivial-httpd.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ostree-trivial-httpd.c'; fi` + +src/rofiles-fuse/rofiles_fuse-main.o: src/rofiles-fuse/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rofiles_fuse_CFLAGS) $(CFLAGS) -MT src/rofiles-fuse/rofiles_fuse-main.o -MD -MP -MF src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Tpo -c -o src/rofiles-fuse/rofiles_fuse-main.o `test -f 'src/rofiles-fuse/main.c' || echo '$(srcdir)/'`src/rofiles-fuse/main.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Tpo src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/rofiles-fuse/main.c' object='src/rofiles-fuse/rofiles_fuse-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rofiles_fuse_CFLAGS) $(CFLAGS) -c -o src/rofiles-fuse/rofiles_fuse-main.o `test -f 'src/rofiles-fuse/main.c' || echo '$(srcdir)/'`src/rofiles-fuse/main.c + +src/rofiles-fuse/rofiles_fuse-main.obj: src/rofiles-fuse/main.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rofiles_fuse_CFLAGS) $(CFLAGS) -MT src/rofiles-fuse/rofiles_fuse-main.obj -MD -MP -MF src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Tpo -c -o src/rofiles-fuse/rofiles_fuse-main.obj `if test -f 'src/rofiles-fuse/main.c'; then $(CYGPATH_W) 'src/rofiles-fuse/main.c'; else $(CYGPATH_W) '$(srcdir)/src/rofiles-fuse/main.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Tpo src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/rofiles-fuse/main.c' object='src/rofiles-fuse/rofiles_fuse-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rofiles_fuse_CFLAGS) $(CFLAGS) -c -o src/rofiles-fuse/rofiles_fuse-main.obj `if test -f 'src/rofiles-fuse/main.c'; then $(CYGPATH_W) 'src/rofiles-fuse/main.c'; else $(CYGPATH_W) '$(srcdir)/src/rofiles-fuse/main.c'; fi` + +libglnx/tests/test_libglnx_errors-libglnx-testlib.o: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_errors_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_errors-libglnx-testlib.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_errors-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_errors-libglnx-testlib.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_errors_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_errors-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c + +libglnx/tests/test_libglnx_errors-libglnx-testlib.obj: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_errors_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_errors-libglnx-testlib.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_errors-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_errors-libglnx-testlib.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_errors_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_errors-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` + +libglnx/tests/test_libglnx_errors-test-libglnx-errors.o: libglnx/tests/test-libglnx-errors.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_errors_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_errors-test-libglnx-errors.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Tpo -c -o libglnx/tests/test_libglnx_errors-test-libglnx-errors.o `test -f 'libglnx/tests/test-libglnx-errors.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-errors.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-errors.c' object='libglnx/tests/test_libglnx_errors-test-libglnx-errors.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_errors_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_errors-test-libglnx-errors.o `test -f 'libglnx/tests/test-libglnx-errors.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-errors.c + +libglnx/tests/test_libglnx_errors-test-libglnx-errors.obj: libglnx/tests/test-libglnx-errors.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_errors_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_errors-test-libglnx-errors.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Tpo -c -o libglnx/tests/test_libglnx_errors-test-libglnx-errors.obj `if test -f 'libglnx/tests/test-libglnx-errors.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-errors.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-errors.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-errors.c' object='libglnx/tests/test_libglnx_errors-test-libglnx-errors.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_errors_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_errors-test-libglnx-errors.obj `if test -f 'libglnx/tests/test-libglnx-errors.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-errors.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-errors.c'; fi` + +libglnx/tests/test_libglnx_fdio-libglnx-testlib.o: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_fdio_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_fdio-libglnx-testlib.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_fdio-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_fdio-libglnx-testlib.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_fdio_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_fdio-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c + +libglnx/tests/test_libglnx_fdio-libglnx-testlib.obj: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_fdio_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_fdio-libglnx-testlib.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_fdio-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_fdio-libglnx-testlib.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_fdio_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_fdio-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` + +libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.o: libglnx/tests/test-libglnx-fdio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_fdio_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Tpo -c -o libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.o `test -f 'libglnx/tests/test-libglnx-fdio.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-fdio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-fdio.c' object='libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_fdio_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.o `test -f 'libglnx/tests/test-libglnx-fdio.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-fdio.c + +libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.obj: libglnx/tests/test-libglnx-fdio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_fdio_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Tpo -c -o libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.obj `if test -f 'libglnx/tests/test-libglnx-fdio.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-fdio.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-fdio.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-fdio.c' object='libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_fdio_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_fdio-test-libglnx-fdio.obj `if test -f 'libglnx/tests/test-libglnx-fdio.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-fdio.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-fdio.c'; fi` + +libglnx/tests/test_libglnx_macros-libglnx-testlib.o: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_macros-libglnx-testlib.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_macros-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_macros-libglnx-testlib.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_macros-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c + +libglnx/tests/test_libglnx_macros-libglnx-testlib.obj: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_macros-libglnx-testlib.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_macros-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_macros-libglnx-testlib.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_macros-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` + +libglnx/tests/test_libglnx_macros-test-libglnx-macros.o: libglnx/tests/test-libglnx-macros.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_macros-test-libglnx-macros.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Tpo -c -o libglnx/tests/test_libglnx_macros-test-libglnx-macros.o `test -f 'libglnx/tests/test-libglnx-macros.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-macros.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-macros.c' object='libglnx/tests/test_libglnx_macros-test-libglnx-macros.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_macros-test-libglnx-macros.o `test -f 'libglnx/tests/test-libglnx-macros.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-macros.c + +libglnx/tests/test_libglnx_macros-test-libglnx-macros.obj: libglnx/tests/test-libglnx-macros.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_macros-test-libglnx-macros.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Tpo -c -o libglnx/tests/test_libglnx_macros-test-libglnx-macros.obj `if test -f 'libglnx/tests/test-libglnx-macros.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-macros.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-macros.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-macros.c' object='libglnx/tests/test_libglnx_macros-test-libglnx-macros.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_macros_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_macros-test-libglnx-macros.obj `if test -f 'libglnx/tests/test-libglnx-macros.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-macros.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-macros.c'; fi` + +libglnx/tests/test_libglnx_shutil-libglnx-testlib.o: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_shutil-libglnx-testlib.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_shutil-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_shutil-libglnx-testlib.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_shutil-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c + +libglnx/tests/test_libglnx_shutil-libglnx-testlib.obj: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_shutil-libglnx-testlib.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_shutil-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_shutil-libglnx-testlib.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_shutil-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` + +libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o: libglnx/tests/test-libglnx-shutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Tpo -c -o libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o `test -f 'libglnx/tests/test-libglnx-shutil.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-shutil.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-shutil.c' object='libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.o `test -f 'libglnx/tests/test-libglnx-shutil.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-shutil.c + +libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj: libglnx/tests/test-libglnx-shutil.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Tpo -c -o libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj `if test -f 'libglnx/tests/test-libglnx-shutil.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-shutil.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-shutil.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-shutil.c' object='libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_shutil_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_shutil-test-libglnx-shutil.obj `if test -f 'libglnx/tests/test-libglnx-shutil.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-shutil.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-shutil.c'; fi` + +libglnx/tests/test_libglnx_xattrs-libglnx-testlib.o: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_xattrs-libglnx-testlib.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_xattrs-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_xattrs-libglnx-testlib.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_xattrs-libglnx-testlib.o `test -f 'libglnx/tests/libglnx-testlib.c' || echo '$(srcdir)/'`libglnx/tests/libglnx-testlib.c + +libglnx/tests/test_libglnx_xattrs-libglnx-testlib.obj: libglnx/tests/libglnx-testlib.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_xattrs-libglnx-testlib.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Tpo -c -o libglnx/tests/test_libglnx_xattrs-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/libglnx-testlib.c' object='libglnx/tests/test_libglnx_xattrs-libglnx-testlib.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_xattrs-libglnx-testlib.obj `if test -f 'libglnx/tests/libglnx-testlib.c'; then $(CYGPATH_W) 'libglnx/tests/libglnx-testlib.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/libglnx-testlib.c'; fi` + +libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o: libglnx/tests/test-libglnx-xattrs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Tpo -c -o libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o `test -f 'libglnx/tests/test-libglnx-xattrs.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-xattrs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-xattrs.c' object='libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.o `test -f 'libglnx/tests/test-libglnx-xattrs.c' || echo '$(srcdir)/'`libglnx/tests/test-libglnx-xattrs.c + +libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.obj: libglnx/tests/test-libglnx-xattrs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -MT libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.obj -MD -MP -MF libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Tpo -c -o libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.obj `if test -f 'libglnx/tests/test-libglnx-xattrs.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-xattrs.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-xattrs.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Tpo libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libglnx/tests/test-libglnx-xattrs.c' object='libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_libglnx_xattrs_CFLAGS) $(CFLAGS) -c -o libglnx/tests/test_libglnx_xattrs-test-libglnx-xattrs.obj `if test -f 'libglnx/tests/test-libglnx-xattrs.c'; then $(CYGPATH_W) 'libglnx/tests/test-libglnx-xattrs.c'; else $(CYGPATH_W) '$(srcdir)/libglnx/tests/test-libglnx-xattrs.c'; fi` + +tests/get_byte_order-get-byte-order.o: tests/get-byte-order.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_get_byte_order_CFLAGS) $(CFLAGS) -MT tests/get_byte_order-get-byte-order.o -MD -MP -MF tests/$(DEPDIR)/get_byte_order-get-byte-order.Tpo -c -o tests/get_byte_order-get-byte-order.o `test -f 'tests/get-byte-order.c' || echo '$(srcdir)/'`tests/get-byte-order.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/get_byte_order-get-byte-order.Tpo tests/$(DEPDIR)/get_byte_order-get-byte-order.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/get-byte-order.c' object='tests/get_byte_order-get-byte-order.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_get_byte_order_CFLAGS) $(CFLAGS) -c -o tests/get_byte_order-get-byte-order.o `test -f 'tests/get-byte-order.c' || echo '$(srcdir)/'`tests/get-byte-order.c + +tests/get_byte_order-get-byte-order.obj: tests/get-byte-order.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_get_byte_order_CFLAGS) $(CFLAGS) -MT tests/get_byte_order-get-byte-order.obj -MD -MP -MF tests/$(DEPDIR)/get_byte_order-get-byte-order.Tpo -c -o tests/get_byte_order-get-byte-order.obj `if test -f 'tests/get-byte-order.c'; then $(CYGPATH_W) 'tests/get-byte-order.c'; else $(CYGPATH_W) '$(srcdir)/tests/get-byte-order.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/get_byte_order-get-byte-order.Tpo tests/$(DEPDIR)/get_byte_order-get-byte-order.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/get-byte-order.c' object='tests/get_byte_order-get-byte-order.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_get_byte_order_CFLAGS) $(CFLAGS) -c -o tests/get_byte_order-get-byte-order.obj `if test -f 'tests/get-byte-order.c'; then $(CYGPATH_W) 'tests/get-byte-order.c'; else $(CYGPATH_W) '$(srcdir)/tests/get-byte-order.c'; fi` + +tests/repo_finder_mount-repo-finder-mount.o: tests/repo-finder-mount.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_repo_finder_mount_CFLAGS) $(CFLAGS) -MT tests/repo_finder_mount-repo-finder-mount.o -MD -MP -MF tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Tpo -c -o tests/repo_finder_mount-repo-finder-mount.o `test -f 'tests/repo-finder-mount.c' || echo '$(srcdir)/'`tests/repo-finder-mount.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Tpo tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/repo-finder-mount.c' object='tests/repo_finder_mount-repo-finder-mount.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_repo_finder_mount_CFLAGS) $(CFLAGS) -c -o tests/repo_finder_mount-repo-finder-mount.o `test -f 'tests/repo-finder-mount.c' || echo '$(srcdir)/'`tests/repo-finder-mount.c + +tests/repo_finder_mount-repo-finder-mount.obj: tests/repo-finder-mount.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_repo_finder_mount_CFLAGS) $(CFLAGS) -MT tests/repo_finder_mount-repo-finder-mount.obj -MD -MP -MF tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Tpo -c -o tests/repo_finder_mount-repo-finder-mount.obj `if test -f 'tests/repo-finder-mount.c'; then $(CYGPATH_W) 'tests/repo-finder-mount.c'; else $(CYGPATH_W) '$(srcdir)/tests/repo-finder-mount.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Tpo tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/repo-finder-mount.c' object='tests/repo_finder_mount-repo-finder-mount.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_repo_finder_mount_CFLAGS) $(CFLAGS) -c -o tests/repo_finder_mount-repo-finder-mount.obj `if test -f 'tests/repo-finder-mount.c'; then $(CYGPATH_W) 'tests/repo-finder-mount.c'; else $(CYGPATH_W) '$(srcdir)/tests/repo-finder-mount.c'; fi` + +tests/test_basic_c-test-basic-c.o: tests/test-basic-c.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_basic_c_CFLAGS) $(CFLAGS) -MT tests/test_basic_c-test-basic-c.o -MD -MP -MF tests/$(DEPDIR)/test_basic_c-test-basic-c.Tpo -c -o tests/test_basic_c-test-basic-c.o `test -f 'tests/test-basic-c.c' || echo '$(srcdir)/'`tests/test-basic-c.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_basic_c-test-basic-c.Tpo tests/$(DEPDIR)/test_basic_c-test-basic-c.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-basic-c.c' object='tests/test_basic_c-test-basic-c.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_basic_c_CFLAGS) $(CFLAGS) -c -o tests/test_basic_c-test-basic-c.o `test -f 'tests/test-basic-c.c' || echo '$(srcdir)/'`tests/test-basic-c.c + +tests/test_basic_c-test-basic-c.obj: tests/test-basic-c.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_basic_c_CFLAGS) $(CFLAGS) -MT tests/test_basic_c-test-basic-c.obj -MD -MP -MF tests/$(DEPDIR)/test_basic_c-test-basic-c.Tpo -c -o tests/test_basic_c-test-basic-c.obj `if test -f 'tests/test-basic-c.c'; then $(CYGPATH_W) 'tests/test-basic-c.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-basic-c.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_basic_c-test-basic-c.Tpo tests/$(DEPDIR)/test_basic_c-test-basic-c.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-basic-c.c' object='tests/test_basic_c-test-basic-c.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_basic_c_CFLAGS) $(CFLAGS) -c -o tests/test_basic_c-test-basic-c.obj `if test -f 'tests/test-basic-c.c'; then $(CYGPATH_W) 'tests/test-basic-c.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-basic-c.c'; fi` + +src/libostree/tests_test_bloom-ostree-bloom.o: src/libostree/ostree-bloom.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bloom_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_bloom-ostree-bloom.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Tpo -c -o src/libostree/tests_test_bloom-ostree-bloom.o `test -f 'src/libostree/ostree-bloom.c' || echo '$(srcdir)/'`src/libostree/ostree-bloom.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Tpo src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-bloom.c' object='src/libostree/tests_test_bloom-ostree-bloom.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bloom_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_bloom-ostree-bloom.o `test -f 'src/libostree/ostree-bloom.c' || echo '$(srcdir)/'`src/libostree/ostree-bloom.c + +src/libostree/tests_test_bloom-ostree-bloom.obj: src/libostree/ostree-bloom.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bloom_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_bloom-ostree-bloom.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Tpo -c -o src/libostree/tests_test_bloom-ostree-bloom.obj `if test -f 'src/libostree/ostree-bloom.c'; then $(CYGPATH_W) 'src/libostree/ostree-bloom.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-bloom.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Tpo src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-bloom.c' object='src/libostree/tests_test_bloom-ostree-bloom.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bloom_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_bloom-ostree-bloom.obj `if test -f 'src/libostree/ostree-bloom.c'; then $(CYGPATH_W) 'src/libostree/ostree-bloom.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-bloom.c'; fi` + +tests/test_bloom-test-bloom.o: tests/test-bloom.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bloom_CFLAGS) $(CFLAGS) -MT tests/test_bloom-test-bloom.o -MD -MP -MF tests/$(DEPDIR)/test_bloom-test-bloom.Tpo -c -o tests/test_bloom-test-bloom.o `test -f 'tests/test-bloom.c' || echo '$(srcdir)/'`tests/test-bloom.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_bloom-test-bloom.Tpo tests/$(DEPDIR)/test_bloom-test-bloom.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-bloom.c' object='tests/test_bloom-test-bloom.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bloom_CFLAGS) $(CFLAGS) -c -o tests/test_bloom-test-bloom.o `test -f 'tests/test-bloom.c' || echo '$(srcdir)/'`tests/test-bloom.c + +tests/test_bloom-test-bloom.obj: tests/test-bloom.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bloom_CFLAGS) $(CFLAGS) -MT tests/test_bloom-test-bloom.obj -MD -MP -MF tests/$(DEPDIR)/test_bloom-test-bloom.Tpo -c -o tests/test_bloom-test-bloom.obj `if test -f 'tests/test-bloom.c'; then $(CYGPATH_W) 'tests/test-bloom.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-bloom.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_bloom-test-bloom.Tpo tests/$(DEPDIR)/test_bloom-test-bloom.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-bloom.c' object='tests/test_bloom-test-bloom.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bloom_CFLAGS) $(CFLAGS) -c -o tests/test_bloom-test-bloom.obj `if test -f 'tests/test-bloom.c'; then $(CYGPATH_W) 'tests/test-bloom.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-bloom.c'; fi` + +tests/test_bsdiff-test-bsdiff.o: tests/test-bsdiff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bsdiff_CFLAGS) $(CFLAGS) -MT tests/test_bsdiff-test-bsdiff.o -MD -MP -MF tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Tpo -c -o tests/test_bsdiff-test-bsdiff.o `test -f 'tests/test-bsdiff.c' || echo '$(srcdir)/'`tests/test-bsdiff.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Tpo tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-bsdiff.c' object='tests/test_bsdiff-test-bsdiff.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bsdiff_CFLAGS) $(CFLAGS) -c -o tests/test_bsdiff-test-bsdiff.o `test -f 'tests/test-bsdiff.c' || echo '$(srcdir)/'`tests/test-bsdiff.c + +tests/test_bsdiff-test-bsdiff.obj: tests/test-bsdiff.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bsdiff_CFLAGS) $(CFLAGS) -MT tests/test_bsdiff-test-bsdiff.obj -MD -MP -MF tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Tpo -c -o tests/test_bsdiff-test-bsdiff.obj `if test -f 'tests/test-bsdiff.c'; then $(CYGPATH_W) 'tests/test-bsdiff.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-bsdiff.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Tpo tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-bsdiff.c' object='tests/test_bsdiff-test-bsdiff.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_bsdiff_CFLAGS) $(CFLAGS) -c -o tests/test_bsdiff-test-bsdiff.obj `if test -f 'tests/test-bsdiff.c'; then $(CYGPATH_W) 'tests/test-bsdiff.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-bsdiff.c'; fi` + +src/libostree/tests_test_checksum-ostree-core.o: src/libostree/ostree-core.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_checksum-ostree-core.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Tpo -c -o src/libostree/tests_test_checksum-ostree-core.o `test -f 'src/libostree/ostree-core.c' || echo '$(srcdir)/'`src/libostree/ostree-core.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Tpo src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-core.c' object='src/libostree/tests_test_checksum-ostree-core.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_checksum-ostree-core.o `test -f 'src/libostree/ostree-core.c' || echo '$(srcdir)/'`src/libostree/ostree-core.c + +src/libostree/tests_test_checksum-ostree-core.obj: src/libostree/ostree-core.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_checksum-ostree-core.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Tpo -c -o src/libostree/tests_test_checksum-ostree-core.obj `if test -f 'src/libostree/ostree-core.c'; then $(CYGPATH_W) 'src/libostree/ostree-core.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-core.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Tpo src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-core.c' object='src/libostree/tests_test_checksum-ostree-core.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_checksum-ostree-core.obj `if test -f 'src/libostree/ostree-core.c'; then $(CYGPATH_W) 'src/libostree/ostree-core.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-core.c'; fi` + +src/libostree/tests_test_checksum-ostree-varint.o: src/libostree/ostree-varint.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_checksum-ostree-varint.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Tpo -c -o src/libostree/tests_test_checksum-ostree-varint.o `test -f 'src/libostree/ostree-varint.c' || echo '$(srcdir)/'`src/libostree/ostree-varint.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Tpo src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-varint.c' object='src/libostree/tests_test_checksum-ostree-varint.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_checksum-ostree-varint.o `test -f 'src/libostree/ostree-varint.c' || echo '$(srcdir)/'`src/libostree/ostree-varint.c + +src/libostree/tests_test_checksum-ostree-varint.obj: src/libostree/ostree-varint.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_checksum-ostree-varint.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Tpo -c -o src/libostree/tests_test_checksum-ostree-varint.obj `if test -f 'src/libostree/ostree-varint.c'; then $(CYGPATH_W) 'src/libostree/ostree-varint.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-varint.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Tpo src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-varint.c' object='src/libostree/tests_test_checksum-ostree-varint.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_checksum-ostree-varint.obj `if test -f 'src/libostree/ostree-varint.c'; then $(CYGPATH_W) 'src/libostree/ostree-varint.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-varint.c'; fi` + +tests/test_checksum-test-checksum.o: tests/test-checksum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -MT tests/test_checksum-test-checksum.o -MD -MP -MF tests/$(DEPDIR)/test_checksum-test-checksum.Tpo -c -o tests/test_checksum-test-checksum.o `test -f 'tests/test-checksum.c' || echo '$(srcdir)/'`tests/test-checksum.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_checksum-test-checksum.Tpo tests/$(DEPDIR)/test_checksum-test-checksum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-checksum.c' object='tests/test_checksum-test-checksum.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -c -o tests/test_checksum-test-checksum.o `test -f 'tests/test-checksum.c' || echo '$(srcdir)/'`tests/test-checksum.c + +tests/test_checksum-test-checksum.obj: tests/test-checksum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -MT tests/test_checksum-test-checksum.obj -MD -MP -MF tests/$(DEPDIR)/test_checksum-test-checksum.Tpo -c -o tests/test_checksum-test-checksum.obj `if test -f 'tests/test-checksum.c'; then $(CYGPATH_W) 'tests/test-checksum.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-checksum.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_checksum-test-checksum.Tpo tests/$(DEPDIR)/test_checksum-test-checksum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-checksum.c' object='tests/test_checksum-test-checksum.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_checksum_CFLAGS) $(CFLAGS) -c -o tests/test_checksum-test-checksum.obj `if test -f 'tests/test-checksum.c'; then $(CYGPATH_W) 'tests/test-checksum.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-checksum.c'; fi` + +tests/test_gpg_verify_result-test-gpg-verify-result.o: tests/test-gpg-verify-result.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_gpg_verify_result_CFLAGS) $(CFLAGS) -MT tests/test_gpg_verify_result-test-gpg-verify-result.o -MD -MP -MF tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Tpo -c -o tests/test_gpg_verify_result-test-gpg-verify-result.o `test -f 'tests/test-gpg-verify-result.c' || echo '$(srcdir)/'`tests/test-gpg-verify-result.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Tpo tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-gpg-verify-result.c' object='tests/test_gpg_verify_result-test-gpg-verify-result.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_gpg_verify_result_CFLAGS) $(CFLAGS) -c -o tests/test_gpg_verify_result-test-gpg-verify-result.o `test -f 'tests/test-gpg-verify-result.c' || echo '$(srcdir)/'`tests/test-gpg-verify-result.c + +tests/test_gpg_verify_result-test-gpg-verify-result.obj: tests/test-gpg-verify-result.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_gpg_verify_result_CFLAGS) $(CFLAGS) -MT tests/test_gpg_verify_result-test-gpg-verify-result.obj -MD -MP -MF tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Tpo -c -o tests/test_gpg_verify_result-test-gpg-verify-result.obj `if test -f 'tests/test-gpg-verify-result.c'; then $(CYGPATH_W) 'tests/test-gpg-verify-result.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-gpg-verify-result.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Tpo tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-gpg-verify-result.c' object='tests/test_gpg_verify_result-test-gpg-verify-result.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_gpg_verify_result_CFLAGS) $(CFLAGS) -c -o tests/test_gpg_verify_result-test-gpg-verify-result.obj `if test -f 'tests/test-gpg-verify-result.c'; then $(CYGPATH_W) 'tests/test-gpg-verify-result.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-gpg-verify-result.c'; fi` + +tests/test_include_ostree_h-test-include-ostree-h.o: tests/test-include-ostree-h.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tests_test_include_ostree_h_CPPFLAGS) $(CPPFLAGS) $(tests_test_include_ostree_h_CFLAGS) $(CFLAGS) -MT tests/test_include_ostree_h-test-include-ostree-h.o -MD -MP -MF tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Tpo -c -o tests/test_include_ostree_h-test-include-ostree-h.o `test -f 'tests/test-include-ostree-h.c' || echo '$(srcdir)/'`tests/test-include-ostree-h.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Tpo tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-include-ostree-h.c' object='tests/test_include_ostree_h-test-include-ostree-h.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tests_test_include_ostree_h_CPPFLAGS) $(CPPFLAGS) $(tests_test_include_ostree_h_CFLAGS) $(CFLAGS) -c -o tests/test_include_ostree_h-test-include-ostree-h.o `test -f 'tests/test-include-ostree-h.c' || echo '$(srcdir)/'`tests/test-include-ostree-h.c + +tests/test_include_ostree_h-test-include-ostree-h.obj: tests/test-include-ostree-h.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tests_test_include_ostree_h_CPPFLAGS) $(CPPFLAGS) $(tests_test_include_ostree_h_CFLAGS) $(CFLAGS) -MT tests/test_include_ostree_h-test-include-ostree-h.obj -MD -MP -MF tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Tpo -c -o tests/test_include_ostree_h-test-include-ostree-h.obj `if test -f 'tests/test-include-ostree-h.c'; then $(CYGPATH_W) 'tests/test-include-ostree-h.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-include-ostree-h.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Tpo tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-include-ostree-h.c' object='tests/test_include_ostree_h-test-include-ostree-h.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(tests_test_include_ostree_h_CPPFLAGS) $(CPPFLAGS) $(tests_test_include_ostree_h_CFLAGS) $(CFLAGS) -c -o tests/test_include_ostree_h-test-include-ostree-h.obj `if test -f 'tests/test-include-ostree-h.c'; then $(CYGPATH_W) 'tests/test-include-ostree-h.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-include-ostree-h.c'; fi` + +src/libostree/tests_test_kargs-ostree-kernel-args.o: src/libostree/ostree-kernel-args.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_kargs_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_kargs-ostree-kernel-args.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Tpo -c -o src/libostree/tests_test_kargs-ostree-kernel-args.o `test -f 'src/libostree/ostree-kernel-args.c' || echo '$(srcdir)/'`src/libostree/ostree-kernel-args.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Tpo src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-kernel-args.c' object='src/libostree/tests_test_kargs-ostree-kernel-args.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_kargs_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_kargs-ostree-kernel-args.o `test -f 'src/libostree/ostree-kernel-args.c' || echo '$(srcdir)/'`src/libostree/ostree-kernel-args.c + +src/libostree/tests_test_kargs-ostree-kernel-args.obj: src/libostree/ostree-kernel-args.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_kargs_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_kargs-ostree-kernel-args.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Tpo -c -o src/libostree/tests_test_kargs-ostree-kernel-args.obj `if test -f 'src/libostree/ostree-kernel-args.c'; then $(CYGPATH_W) 'src/libostree/ostree-kernel-args.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-kernel-args.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Tpo src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-kernel-args.c' object='src/libostree/tests_test_kargs-ostree-kernel-args.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_kargs_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_kargs-ostree-kernel-args.obj `if test -f 'src/libostree/ostree-kernel-args.c'; then $(CYGPATH_W) 'src/libostree/ostree-kernel-args.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-kernel-args.c'; fi` + +tests/test_kargs-test-kargs.o: tests/test-kargs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_kargs_CFLAGS) $(CFLAGS) -MT tests/test_kargs-test-kargs.o -MD -MP -MF tests/$(DEPDIR)/test_kargs-test-kargs.Tpo -c -o tests/test_kargs-test-kargs.o `test -f 'tests/test-kargs.c' || echo '$(srcdir)/'`tests/test-kargs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_kargs-test-kargs.Tpo tests/$(DEPDIR)/test_kargs-test-kargs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-kargs.c' object='tests/test_kargs-test-kargs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_kargs_CFLAGS) $(CFLAGS) -c -o tests/test_kargs-test-kargs.o `test -f 'tests/test-kargs.c' || echo '$(srcdir)/'`tests/test-kargs.c + +tests/test_kargs-test-kargs.obj: tests/test-kargs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_kargs_CFLAGS) $(CFLAGS) -MT tests/test_kargs-test-kargs.obj -MD -MP -MF tests/$(DEPDIR)/test_kargs-test-kargs.Tpo -c -o tests/test_kargs-test-kargs.obj `if test -f 'tests/test-kargs.c'; then $(CYGPATH_W) 'tests/test-kargs.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-kargs.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_kargs-test-kargs.Tpo tests/$(DEPDIR)/test_kargs-test-kargs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-kargs.c' object='tests/test_kargs-test-kargs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_kargs_CFLAGS) $(CFLAGS) -c -o tests/test_kargs-test-kargs.obj `if test -f 'tests/test-kargs.c'; then $(CYGPATH_W) 'tests/test-kargs.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-kargs.c'; fi` + +tests/test_keyfile_utils-test-keyfile-utils.o: tests/test-keyfile-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_keyfile_utils_CFLAGS) $(CFLAGS) -MT tests/test_keyfile_utils-test-keyfile-utils.o -MD -MP -MF tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Tpo -c -o tests/test_keyfile_utils-test-keyfile-utils.o `test -f 'tests/test-keyfile-utils.c' || echo '$(srcdir)/'`tests/test-keyfile-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Tpo tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-keyfile-utils.c' object='tests/test_keyfile_utils-test-keyfile-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_keyfile_utils_CFLAGS) $(CFLAGS) -c -o tests/test_keyfile_utils-test-keyfile-utils.o `test -f 'tests/test-keyfile-utils.c' || echo '$(srcdir)/'`tests/test-keyfile-utils.c + +tests/test_keyfile_utils-test-keyfile-utils.obj: tests/test-keyfile-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_keyfile_utils_CFLAGS) $(CFLAGS) -MT tests/test_keyfile_utils-test-keyfile-utils.obj -MD -MP -MF tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Tpo -c -o tests/test_keyfile_utils-test-keyfile-utils.obj `if test -f 'tests/test-keyfile-utils.c'; then $(CYGPATH_W) 'tests/test-keyfile-utils.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-keyfile-utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Tpo tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-keyfile-utils.c' object='tests/test_keyfile_utils-test-keyfile-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_keyfile_utils_CFLAGS) $(CFLAGS) -c -o tests/test_keyfile_utils-test-keyfile-utils.obj `if test -f 'tests/test-keyfile-utils.c'; then $(CYGPATH_W) 'tests/test-keyfile-utils.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-keyfile-utils.c'; fi` + +tests/test_libarchive_import-test-libarchive-import.o: tests/test-libarchive-import.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_libarchive_import_CFLAGS) $(CFLAGS) -MT tests/test_libarchive_import-test-libarchive-import.o -MD -MP -MF tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Tpo -c -o tests/test_libarchive_import-test-libarchive-import.o `test -f 'tests/test-libarchive-import.c' || echo '$(srcdir)/'`tests/test-libarchive-import.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Tpo tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-libarchive-import.c' object='tests/test_libarchive_import-test-libarchive-import.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_libarchive_import_CFLAGS) $(CFLAGS) -c -o tests/test_libarchive_import-test-libarchive-import.o `test -f 'tests/test-libarchive-import.c' || echo '$(srcdir)/'`tests/test-libarchive-import.c + +tests/test_libarchive_import-test-libarchive-import.obj: tests/test-libarchive-import.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_libarchive_import_CFLAGS) $(CFLAGS) -MT tests/test_libarchive_import-test-libarchive-import.obj -MD -MP -MF tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Tpo -c -o tests/test_libarchive_import-test-libarchive-import.obj `if test -f 'tests/test-libarchive-import.c'; then $(CYGPATH_W) 'tests/test-libarchive-import.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-libarchive-import.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Tpo tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-libarchive-import.c' object='tests/test_libarchive_import-test-libarchive-import.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_libarchive_import_CFLAGS) $(CFLAGS) -c -o tests/test_libarchive_import-test-libarchive-import.obj `if test -f 'tests/test-libarchive-import.c'; then $(CYGPATH_W) 'tests/test-libarchive-import.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-libarchive-import.c'; fi` + +src/libostree/tests_test_lzma-ostree-lzma-common.o: src/libostree/ostree-lzma-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_lzma-ostree-lzma-common.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Tpo -c -o src/libostree/tests_test_lzma-ostree-lzma-common.o `test -f 'src/libostree/ostree-lzma-common.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Tpo src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-lzma-common.c' object='src/libostree/tests_test_lzma-ostree-lzma-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_lzma-ostree-lzma-common.o `test -f 'src/libostree/ostree-lzma-common.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-common.c + +src/libostree/tests_test_lzma-ostree-lzma-common.obj: src/libostree/ostree-lzma-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_lzma-ostree-lzma-common.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Tpo -c -o src/libostree/tests_test_lzma-ostree-lzma-common.obj `if test -f 'src/libostree/ostree-lzma-common.c'; then $(CYGPATH_W) 'src/libostree/ostree-lzma-common.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-lzma-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Tpo src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-lzma-common.c' object='src/libostree/tests_test_lzma-ostree-lzma-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_lzma-ostree-lzma-common.obj `if test -f 'src/libostree/ostree-lzma-common.c'; then $(CYGPATH_W) 'src/libostree/ostree-lzma-common.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-lzma-common.c'; fi` + +src/libostree/tests_test_lzma-ostree-lzma-compressor.o: src/libostree/ostree-lzma-compressor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_lzma-ostree-lzma-compressor.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Tpo -c -o src/libostree/tests_test_lzma-ostree-lzma-compressor.o `test -f 'src/libostree/ostree-lzma-compressor.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-compressor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Tpo src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-lzma-compressor.c' object='src/libostree/tests_test_lzma-ostree-lzma-compressor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_lzma-ostree-lzma-compressor.o `test -f 'src/libostree/ostree-lzma-compressor.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-compressor.c + +src/libostree/tests_test_lzma-ostree-lzma-compressor.obj: src/libostree/ostree-lzma-compressor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_lzma-ostree-lzma-compressor.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Tpo -c -o src/libostree/tests_test_lzma-ostree-lzma-compressor.obj `if test -f 'src/libostree/ostree-lzma-compressor.c'; then $(CYGPATH_W) 'src/libostree/ostree-lzma-compressor.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-lzma-compressor.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Tpo src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-lzma-compressor.c' object='src/libostree/tests_test_lzma-ostree-lzma-compressor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_lzma-ostree-lzma-compressor.obj `if test -f 'src/libostree/ostree-lzma-compressor.c'; then $(CYGPATH_W) 'src/libostree/ostree-lzma-compressor.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-lzma-compressor.c'; fi` + +src/libostree/tests_test_lzma-ostree-lzma-decompressor.o: src/libostree/ostree-lzma-decompressor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_lzma-ostree-lzma-decompressor.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Tpo -c -o src/libostree/tests_test_lzma-ostree-lzma-decompressor.o `test -f 'src/libostree/ostree-lzma-decompressor.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-decompressor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Tpo src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-lzma-decompressor.c' object='src/libostree/tests_test_lzma-ostree-lzma-decompressor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_lzma-ostree-lzma-decompressor.o `test -f 'src/libostree/ostree-lzma-decompressor.c' || echo '$(srcdir)/'`src/libostree/ostree-lzma-decompressor.c + +src/libostree/tests_test_lzma-ostree-lzma-decompressor.obj: src/libostree/ostree-lzma-decompressor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_lzma-ostree-lzma-decompressor.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Tpo -c -o src/libostree/tests_test_lzma-ostree-lzma-decompressor.obj `if test -f 'src/libostree/ostree-lzma-decompressor.c'; then $(CYGPATH_W) 'src/libostree/ostree-lzma-decompressor.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-lzma-decompressor.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Tpo src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-lzma-decompressor.c' object='src/libostree/tests_test_lzma-ostree-lzma-decompressor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_lzma-ostree-lzma-decompressor.obj `if test -f 'src/libostree/ostree-lzma-decompressor.c'; then $(CYGPATH_W) 'src/libostree/ostree-lzma-decompressor.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-lzma-decompressor.c'; fi` + +tests/test_lzma-test-lzma.o: tests/test-lzma.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -MT tests/test_lzma-test-lzma.o -MD -MP -MF tests/$(DEPDIR)/test_lzma-test-lzma.Tpo -c -o tests/test_lzma-test-lzma.o `test -f 'tests/test-lzma.c' || echo '$(srcdir)/'`tests/test-lzma.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_lzma-test-lzma.Tpo tests/$(DEPDIR)/test_lzma-test-lzma.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-lzma.c' object='tests/test_lzma-test-lzma.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -c -o tests/test_lzma-test-lzma.o `test -f 'tests/test-lzma.c' || echo '$(srcdir)/'`tests/test-lzma.c + +tests/test_lzma-test-lzma.obj: tests/test-lzma.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -MT tests/test_lzma-test-lzma.obj -MD -MP -MF tests/$(DEPDIR)/test_lzma-test-lzma.Tpo -c -o tests/test_lzma-test-lzma.obj `if test -f 'tests/test-lzma.c'; then $(CYGPATH_W) 'tests/test-lzma.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-lzma.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_lzma-test-lzma.Tpo tests/$(DEPDIR)/test_lzma-test-lzma.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-lzma.c' object='tests/test_lzma-test-lzma.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_lzma_CFLAGS) $(CFLAGS) -c -o tests/test_lzma-test-lzma.obj `if test -f 'tests/test-lzma.c'; then $(CYGPATH_W) 'tests/test-lzma.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-lzma.c'; fi` + +tests/test_mutable_tree-test-mutable-tree.o: tests/test-mutable-tree.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_mutable_tree_CFLAGS) $(CFLAGS) -MT tests/test_mutable_tree-test-mutable-tree.o -MD -MP -MF tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Tpo -c -o tests/test_mutable_tree-test-mutable-tree.o `test -f 'tests/test-mutable-tree.c' || echo '$(srcdir)/'`tests/test-mutable-tree.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Tpo tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-mutable-tree.c' object='tests/test_mutable_tree-test-mutable-tree.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_mutable_tree_CFLAGS) $(CFLAGS) -c -o tests/test_mutable_tree-test-mutable-tree.o `test -f 'tests/test-mutable-tree.c' || echo '$(srcdir)/'`tests/test-mutable-tree.c + +tests/test_mutable_tree-test-mutable-tree.obj: tests/test-mutable-tree.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_mutable_tree_CFLAGS) $(CFLAGS) -MT tests/test_mutable_tree-test-mutable-tree.obj -MD -MP -MF tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Tpo -c -o tests/test_mutable_tree-test-mutable-tree.obj `if test -f 'tests/test-mutable-tree.c'; then $(CYGPATH_W) 'tests/test-mutable-tree.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-mutable-tree.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Tpo tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-mutable-tree.c' object='tests/test_mutable_tree-test-mutable-tree.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_mutable_tree_CFLAGS) $(CFLAGS) -c -o tests/test_mutable_tree-test-mutable-tree.obj `if test -f 'tests/test-mutable-tree.c'; then $(CYGPATH_W) 'tests/test-mutable-tree.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-mutable-tree.c'; fi` + +tests/test_ot_opt_utils-test-ot-opt-utils.o: tests/test-ot-opt-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_opt_utils_CFLAGS) $(CFLAGS) -MT tests/test_ot_opt_utils-test-ot-opt-utils.o -MD -MP -MF tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Tpo -c -o tests/test_ot_opt_utils-test-ot-opt-utils.o `test -f 'tests/test-ot-opt-utils.c' || echo '$(srcdir)/'`tests/test-ot-opt-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Tpo tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-ot-opt-utils.c' object='tests/test_ot_opt_utils-test-ot-opt-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_opt_utils_CFLAGS) $(CFLAGS) -c -o tests/test_ot_opt_utils-test-ot-opt-utils.o `test -f 'tests/test-ot-opt-utils.c' || echo '$(srcdir)/'`tests/test-ot-opt-utils.c + +tests/test_ot_opt_utils-test-ot-opt-utils.obj: tests/test-ot-opt-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_opt_utils_CFLAGS) $(CFLAGS) -MT tests/test_ot_opt_utils-test-ot-opt-utils.obj -MD -MP -MF tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Tpo -c -o tests/test_ot_opt_utils-test-ot-opt-utils.obj `if test -f 'tests/test-ot-opt-utils.c'; then $(CYGPATH_W) 'tests/test-ot-opt-utils.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-ot-opt-utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Tpo tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-ot-opt-utils.c' object='tests/test_ot_opt_utils-test-ot-opt-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_opt_utils_CFLAGS) $(CFLAGS) -c -o tests/test_ot_opt_utils-test-ot-opt-utils.obj `if test -f 'tests/test-ot-opt-utils.c'; then $(CYGPATH_W) 'tests/test-ot-opt-utils.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-ot-opt-utils.c'; fi` + +tests/test_ot_tool_util-test-ot-tool-util.o: tests/test-ot-tool-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_tool_util_CFLAGS) $(CFLAGS) -MT tests/test_ot_tool_util-test-ot-tool-util.o -MD -MP -MF tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Tpo -c -o tests/test_ot_tool_util-test-ot-tool-util.o `test -f 'tests/test-ot-tool-util.c' || echo '$(srcdir)/'`tests/test-ot-tool-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Tpo tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-ot-tool-util.c' object='tests/test_ot_tool_util-test-ot-tool-util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_tool_util_CFLAGS) $(CFLAGS) -c -o tests/test_ot_tool_util-test-ot-tool-util.o `test -f 'tests/test-ot-tool-util.c' || echo '$(srcdir)/'`tests/test-ot-tool-util.c + +tests/test_ot_tool_util-test-ot-tool-util.obj: tests/test-ot-tool-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_tool_util_CFLAGS) $(CFLAGS) -MT tests/test_ot_tool_util-test-ot-tool-util.obj -MD -MP -MF tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Tpo -c -o tests/test_ot_tool_util-test-ot-tool-util.obj `if test -f 'tests/test-ot-tool-util.c'; then $(CYGPATH_W) 'tests/test-ot-tool-util.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-ot-tool-util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Tpo tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-ot-tool-util.c' object='tests/test_ot_tool_util-test-ot-tool-util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_tool_util_CFLAGS) $(CFLAGS) -c -o tests/test_ot_tool_util-test-ot-tool-util.obj `if test -f 'tests/test-ot-tool-util.c'; then $(CYGPATH_W) 'tests/test-ot-tool-util.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-ot-tool-util.c'; fi` + +tests/test_ot_unix_utils-test-ot-unix-utils.o: tests/test-ot-unix-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_unix_utils_CFLAGS) $(CFLAGS) -MT tests/test_ot_unix_utils-test-ot-unix-utils.o -MD -MP -MF tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Tpo -c -o tests/test_ot_unix_utils-test-ot-unix-utils.o `test -f 'tests/test-ot-unix-utils.c' || echo '$(srcdir)/'`tests/test-ot-unix-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Tpo tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-ot-unix-utils.c' object='tests/test_ot_unix_utils-test-ot-unix-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_unix_utils_CFLAGS) $(CFLAGS) -c -o tests/test_ot_unix_utils-test-ot-unix-utils.o `test -f 'tests/test-ot-unix-utils.c' || echo '$(srcdir)/'`tests/test-ot-unix-utils.c + +tests/test_ot_unix_utils-test-ot-unix-utils.obj: tests/test-ot-unix-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_unix_utils_CFLAGS) $(CFLAGS) -MT tests/test_ot_unix_utils-test-ot-unix-utils.obj -MD -MP -MF tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Tpo -c -o tests/test_ot_unix_utils-test-ot-unix-utils.obj `if test -f 'tests/test-ot-unix-utils.c'; then $(CYGPATH_W) 'tests/test-ot-unix-utils.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-ot-unix-utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Tpo tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-ot-unix-utils.c' object='tests/test_ot_unix_utils-test-ot-unix-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_ot_unix_utils_CFLAGS) $(CFLAGS) -c -o tests/test_ot_unix_utils-test-ot-unix-utils.obj `if test -f 'tests/test-ot-unix-utils.c'; then $(CYGPATH_W) 'tests/test-ot-unix-utils.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-ot-unix-utils.c'; fi` + +tests/test_pull_c-test-pull-c.o: tests/test-pull-c.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_pull_c_CFLAGS) $(CFLAGS) -MT tests/test_pull_c-test-pull-c.o -MD -MP -MF tests/$(DEPDIR)/test_pull_c-test-pull-c.Tpo -c -o tests/test_pull_c-test-pull-c.o `test -f 'tests/test-pull-c.c' || echo '$(srcdir)/'`tests/test-pull-c.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_pull_c-test-pull-c.Tpo tests/$(DEPDIR)/test_pull_c-test-pull-c.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-pull-c.c' object='tests/test_pull_c-test-pull-c.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_pull_c_CFLAGS) $(CFLAGS) -c -o tests/test_pull_c-test-pull-c.o `test -f 'tests/test-pull-c.c' || echo '$(srcdir)/'`tests/test-pull-c.c + +tests/test_pull_c-test-pull-c.obj: tests/test-pull-c.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_pull_c_CFLAGS) $(CFLAGS) -MT tests/test_pull_c-test-pull-c.obj -MD -MP -MF tests/$(DEPDIR)/test_pull_c-test-pull-c.Tpo -c -o tests/test_pull_c-test-pull-c.obj `if test -f 'tests/test-pull-c.c'; then $(CYGPATH_W) 'tests/test-pull-c.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-pull-c.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_pull_c-test-pull-c.Tpo tests/$(DEPDIR)/test_pull_c-test-pull-c.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-pull-c.c' object='tests/test_pull_c-test-pull-c.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_pull_c_CFLAGS) $(CFLAGS) -c -o tests/test_pull_c-test-pull-c.obj `if test -f 'tests/test-pull-c.c'; then $(CYGPATH_W) 'tests/test-pull-c.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-pull-c.c'; fi` + +tests/test_repo-test-repo.o: tests/test-repo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_CFLAGS) $(CFLAGS) -MT tests/test_repo-test-repo.o -MD -MP -MF tests/$(DEPDIR)/test_repo-test-repo.Tpo -c -o tests/test_repo-test-repo.o `test -f 'tests/test-repo.c' || echo '$(srcdir)/'`tests/test-repo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_repo-test-repo.Tpo tests/$(DEPDIR)/test_repo-test-repo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-repo.c' object='tests/test_repo-test-repo.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_CFLAGS) $(CFLAGS) -c -o tests/test_repo-test-repo.o `test -f 'tests/test-repo.c' || echo '$(srcdir)/'`tests/test-repo.c + +tests/test_repo-test-repo.obj: tests/test-repo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_CFLAGS) $(CFLAGS) -MT tests/test_repo-test-repo.obj -MD -MP -MF tests/$(DEPDIR)/test_repo-test-repo.Tpo -c -o tests/test_repo-test-repo.obj `if test -f 'tests/test-repo.c'; then $(CYGPATH_W) 'tests/test-repo.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-repo.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_repo-test-repo.Tpo tests/$(DEPDIR)/test_repo-test-repo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-repo.c' object='tests/test_repo-test-repo.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_CFLAGS) $(CFLAGS) -c -o tests/test_repo-test-repo.obj `if test -f 'tests/test-repo.c'; then $(CYGPATH_W) 'tests/test-repo.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-repo.c'; fi` + +src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.o: src/libostree/ostree-repo-finder-avahi-parser.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Tpo -c -o src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.o `test -f 'src/libostree/ostree-repo-finder-avahi-parser.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-avahi-parser.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Tpo src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-finder-avahi-parser.c' object='src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.o `test -f 'src/libostree/ostree-repo-finder-avahi-parser.c' || echo '$(srcdir)/'`src/libostree/ostree-repo-finder-avahi-parser.c + +src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.obj: src/libostree/ostree-repo-finder-avahi-parser.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Tpo -c -o src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.obj `if test -f 'src/libostree/ostree-repo-finder-avahi-parser.c'; then $(CYGPATH_W) 'src/libostree/ostree-repo-finder-avahi-parser.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-repo-finder-avahi-parser.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Tpo src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-repo-finder-avahi-parser.c' object='src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.obj `if test -f 'src/libostree/ostree-repo-finder-avahi-parser.c'; then $(CYGPATH_W) 'src/libostree/ostree-repo-finder-avahi-parser.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-repo-finder-avahi-parser.c'; fi` + +tests/test_repo_finder_avahi-test-repo-finder-avahi.o: tests/test-repo-finder-avahi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) -MT tests/test_repo_finder_avahi-test-repo-finder-avahi.o -MD -MP -MF tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Tpo -c -o tests/test_repo_finder_avahi-test-repo-finder-avahi.o `test -f 'tests/test-repo-finder-avahi.c' || echo '$(srcdir)/'`tests/test-repo-finder-avahi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Tpo tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-repo-finder-avahi.c' object='tests/test_repo_finder_avahi-test-repo-finder-avahi.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) -c -o tests/test_repo_finder_avahi-test-repo-finder-avahi.o `test -f 'tests/test-repo-finder-avahi.c' || echo '$(srcdir)/'`tests/test-repo-finder-avahi.c + +tests/test_repo_finder_avahi-test-repo-finder-avahi.obj: tests/test-repo-finder-avahi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) -MT tests/test_repo_finder_avahi-test-repo-finder-avahi.obj -MD -MP -MF tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Tpo -c -o tests/test_repo_finder_avahi-test-repo-finder-avahi.obj `if test -f 'tests/test-repo-finder-avahi.c'; then $(CYGPATH_W) 'tests/test-repo-finder-avahi.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-repo-finder-avahi.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Tpo tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-repo-finder-avahi.c' object='tests/test_repo_finder_avahi-test-repo-finder-avahi.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_avahi_CFLAGS) $(CFLAGS) -c -o tests/test_repo_finder_avahi-test-repo-finder-avahi.obj `if test -f 'tests/test-repo-finder-avahi.c'; then $(CYGPATH_W) 'tests/test-repo-finder-avahi.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-repo-finder-avahi.c'; fi` + +tests/test_repo_finder_config-test-repo-finder-config.o: tests/test-repo-finder-config.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_config_CFLAGS) $(CFLAGS) -MT tests/test_repo_finder_config-test-repo-finder-config.o -MD -MP -MF tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Tpo -c -o tests/test_repo_finder_config-test-repo-finder-config.o `test -f 'tests/test-repo-finder-config.c' || echo '$(srcdir)/'`tests/test-repo-finder-config.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Tpo tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-repo-finder-config.c' object='tests/test_repo_finder_config-test-repo-finder-config.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_config_CFLAGS) $(CFLAGS) -c -o tests/test_repo_finder_config-test-repo-finder-config.o `test -f 'tests/test-repo-finder-config.c' || echo '$(srcdir)/'`tests/test-repo-finder-config.c + +tests/test_repo_finder_config-test-repo-finder-config.obj: tests/test-repo-finder-config.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_config_CFLAGS) $(CFLAGS) -MT tests/test_repo_finder_config-test-repo-finder-config.obj -MD -MP -MF tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Tpo -c -o tests/test_repo_finder_config-test-repo-finder-config.obj `if test -f 'tests/test-repo-finder-config.c'; then $(CYGPATH_W) 'tests/test-repo-finder-config.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-repo-finder-config.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Tpo tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-repo-finder-config.c' object='tests/test_repo_finder_config-test-repo-finder-config.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_config_CFLAGS) $(CFLAGS) -c -o tests/test_repo_finder_config-test-repo-finder-config.obj `if test -f 'tests/test-repo-finder-config.c'; then $(CYGPATH_W) 'tests/test-repo-finder-config.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-repo-finder-config.c'; fi` + +tests/test_repo_finder_mount-test-repo-finder-mount.o: tests/test-repo-finder-mount.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_mount_CFLAGS) $(CFLAGS) -MT tests/test_repo_finder_mount-test-repo-finder-mount.o -MD -MP -MF tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Tpo -c -o tests/test_repo_finder_mount-test-repo-finder-mount.o `test -f 'tests/test-repo-finder-mount.c' || echo '$(srcdir)/'`tests/test-repo-finder-mount.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Tpo tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-repo-finder-mount.c' object='tests/test_repo_finder_mount-test-repo-finder-mount.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_mount_CFLAGS) $(CFLAGS) -c -o tests/test_repo_finder_mount-test-repo-finder-mount.o `test -f 'tests/test-repo-finder-mount.c' || echo '$(srcdir)/'`tests/test-repo-finder-mount.c + +tests/test_repo_finder_mount-test-repo-finder-mount.obj: tests/test-repo-finder-mount.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_mount_CFLAGS) $(CFLAGS) -MT tests/test_repo_finder_mount-test-repo-finder-mount.obj -MD -MP -MF tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Tpo -c -o tests/test_repo_finder_mount-test-repo-finder-mount.obj `if test -f 'tests/test-repo-finder-mount.c'; then $(CYGPATH_W) 'tests/test-repo-finder-mount.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-repo-finder-mount.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Tpo tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-repo-finder-mount.c' object='tests/test_repo_finder_mount-test-repo-finder-mount.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_repo_finder_mount_CFLAGS) $(CFLAGS) -c -o tests/test_repo_finder_mount-test-repo-finder-mount.obj `if test -f 'tests/test-repo-finder-mount.c'; then $(CYGPATH_W) 'tests/test-repo-finder-mount.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-repo-finder-mount.c'; fi` + +src/libostree/tests_test_rollsum-ostree-rollsum.o: src/libostree/ostree-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_rollsum-ostree-rollsum.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Tpo -c -o src/libostree/tests_test_rollsum-ostree-rollsum.o `test -f 'src/libostree/ostree-rollsum.c' || echo '$(srcdir)/'`src/libostree/ostree-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Tpo src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-rollsum.c' object='src/libostree/tests_test_rollsum-ostree-rollsum.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_rollsum-ostree-rollsum.o `test -f 'src/libostree/ostree-rollsum.c' || echo '$(srcdir)/'`src/libostree/ostree-rollsum.c + +src/libostree/tests_test_rollsum-ostree-rollsum.obj: src/libostree/ostree-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_rollsum-ostree-rollsum.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Tpo -c -o src/libostree/tests_test_rollsum-ostree-rollsum.obj `if test -f 'src/libostree/ostree-rollsum.c'; then $(CYGPATH_W) 'src/libostree/ostree-rollsum.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-rollsum.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Tpo src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-rollsum.c' object='src/libostree/tests_test_rollsum-ostree-rollsum.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_rollsum-ostree-rollsum.obj `if test -f 'src/libostree/ostree-rollsum.c'; then $(CYGPATH_W) 'src/libostree/ostree-rollsum.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-rollsum.c'; fi` + +tests/test_rollsum-test-rollsum.o: tests/test-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_CFLAGS) $(CFLAGS) -MT tests/test_rollsum-test-rollsum.o -MD -MP -MF tests/$(DEPDIR)/test_rollsum-test-rollsum.Tpo -c -o tests/test_rollsum-test-rollsum.o `test -f 'tests/test-rollsum.c' || echo '$(srcdir)/'`tests/test-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_rollsum-test-rollsum.Tpo tests/$(DEPDIR)/test_rollsum-test-rollsum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-rollsum.c' object='tests/test_rollsum-test-rollsum.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_CFLAGS) $(CFLAGS) -c -o tests/test_rollsum-test-rollsum.o `test -f 'tests/test-rollsum.c' || echo '$(srcdir)/'`tests/test-rollsum.c + +tests/test_rollsum-test-rollsum.obj: tests/test-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_CFLAGS) $(CFLAGS) -MT tests/test_rollsum-test-rollsum.obj -MD -MP -MF tests/$(DEPDIR)/test_rollsum-test-rollsum.Tpo -c -o tests/test_rollsum-test-rollsum.obj `if test -f 'tests/test-rollsum.c'; then $(CYGPATH_W) 'tests/test-rollsum.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-rollsum.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_rollsum-test-rollsum.Tpo tests/$(DEPDIR)/test_rollsum-test-rollsum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-rollsum.c' object='tests/test_rollsum-test-rollsum.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_CFLAGS) $(CFLAGS) -c -o tests/test_rollsum-test-rollsum.obj `if test -f 'tests/test-rollsum.c'; then $(CYGPATH_W) 'tests/test-rollsum.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-rollsum.c'; fi` + +src/libostree/tests_test_rollsum_cli-ostree-rollsum.o: src/libostree/ostree-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_rollsum_cli-ostree-rollsum.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Tpo -c -o src/libostree/tests_test_rollsum_cli-ostree-rollsum.o `test -f 'src/libostree/ostree-rollsum.c' || echo '$(srcdir)/'`src/libostree/ostree-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Tpo src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-rollsum.c' object='src/libostree/tests_test_rollsum_cli-ostree-rollsum.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_rollsum_cli-ostree-rollsum.o `test -f 'src/libostree/ostree-rollsum.c' || echo '$(srcdir)/'`src/libostree/ostree-rollsum.c + +src/libostree/tests_test_rollsum_cli-ostree-rollsum.obj: src/libostree/ostree-rollsum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_rollsum_cli-ostree-rollsum.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Tpo -c -o src/libostree/tests_test_rollsum_cli-ostree-rollsum.obj `if test -f 'src/libostree/ostree-rollsum.c'; then $(CYGPATH_W) 'src/libostree/ostree-rollsum.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-rollsum.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Tpo src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-rollsum.c' object='src/libostree/tests_test_rollsum_cli-ostree-rollsum.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_rollsum_cli-ostree-rollsum.obj `if test -f 'src/libostree/ostree-rollsum.c'; then $(CYGPATH_W) 'src/libostree/ostree-rollsum.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-rollsum.c'; fi` + +tests/test_rollsum_cli-test-rollsum-cli.o: tests/test-rollsum-cli.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) -MT tests/test_rollsum_cli-test-rollsum-cli.o -MD -MP -MF tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Tpo -c -o tests/test_rollsum_cli-test-rollsum-cli.o `test -f 'tests/test-rollsum-cli.c' || echo '$(srcdir)/'`tests/test-rollsum-cli.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Tpo tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-rollsum-cli.c' object='tests/test_rollsum_cli-test-rollsum-cli.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) -c -o tests/test_rollsum_cli-test-rollsum-cli.o `test -f 'tests/test-rollsum-cli.c' || echo '$(srcdir)/'`tests/test-rollsum-cli.c + +tests/test_rollsum_cli-test-rollsum-cli.obj: tests/test-rollsum-cli.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) -MT tests/test_rollsum_cli-test-rollsum-cli.obj -MD -MP -MF tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Tpo -c -o tests/test_rollsum_cli-test-rollsum-cli.obj `if test -f 'tests/test-rollsum-cli.c'; then $(CYGPATH_W) 'tests/test-rollsum-cli.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-rollsum-cli.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Tpo tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-rollsum-cli.c' object='tests/test_rollsum_cli-test-rollsum-cli.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_rollsum_cli_CFLAGS) $(CFLAGS) -c -o tests/test_rollsum_cli-test-rollsum-cli.obj `if test -f 'tests/test-rollsum-cli.c'; then $(CYGPATH_W) 'tests/test-rollsum-cli.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-rollsum-cli.c'; fi` + +tests/test_sysroot_c-test-sysroot-c.o: tests/test-sysroot-c.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_sysroot_c_CFLAGS) $(CFLAGS) -MT tests/test_sysroot_c-test-sysroot-c.o -MD -MP -MF tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Tpo -c -o tests/test_sysroot_c-test-sysroot-c.o `test -f 'tests/test-sysroot-c.c' || echo '$(srcdir)/'`tests/test-sysroot-c.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Tpo tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-sysroot-c.c' object='tests/test_sysroot_c-test-sysroot-c.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_sysroot_c_CFLAGS) $(CFLAGS) -c -o tests/test_sysroot_c-test-sysroot-c.o `test -f 'tests/test-sysroot-c.c' || echo '$(srcdir)/'`tests/test-sysroot-c.c + +tests/test_sysroot_c-test-sysroot-c.obj: tests/test-sysroot-c.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_sysroot_c_CFLAGS) $(CFLAGS) -MT tests/test_sysroot_c-test-sysroot-c.obj -MD -MP -MF tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Tpo -c -o tests/test_sysroot_c-test-sysroot-c.obj `if test -f 'tests/test-sysroot-c.c'; then $(CYGPATH_W) 'tests/test-sysroot-c.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-sysroot-c.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Tpo tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-sysroot-c.c' object='tests/test_sysroot_c-test-sysroot-c.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_sysroot_c_CFLAGS) $(CFLAGS) -c -o tests/test_sysroot_c-test-sysroot-c.obj `if test -f 'tests/test-sysroot-c.c'; then $(CYGPATH_W) 'tests/test-sysroot-c.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-sysroot-c.c'; fi` + +src/libostree/tests_test_varint-ostree-varint.o: src/libostree/ostree-varint.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_varint_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_varint-ostree-varint.o -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Tpo -c -o src/libostree/tests_test_varint-ostree-varint.o `test -f 'src/libostree/ostree-varint.c' || echo '$(srcdir)/'`src/libostree/ostree-varint.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Tpo src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-varint.c' object='src/libostree/tests_test_varint-ostree-varint.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_varint_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_varint-ostree-varint.o `test -f 'src/libostree/ostree-varint.c' || echo '$(srcdir)/'`src/libostree/ostree-varint.c + +src/libostree/tests_test_varint-ostree-varint.obj: src/libostree/ostree-varint.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_varint_CFLAGS) $(CFLAGS) -MT src/libostree/tests_test_varint-ostree-varint.obj -MD -MP -MF src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Tpo -c -o src/libostree/tests_test_varint-ostree-varint.obj `if test -f 'src/libostree/ostree-varint.c'; then $(CYGPATH_W) 'src/libostree/ostree-varint.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-varint.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Tpo src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-varint.c' object='src/libostree/tests_test_varint-ostree-varint.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_varint_CFLAGS) $(CFLAGS) -c -o src/libostree/tests_test_varint-ostree-varint.obj `if test -f 'src/libostree/ostree-varint.c'; then $(CYGPATH_W) 'src/libostree/ostree-varint.c'; else $(CYGPATH_W) '$(srcdir)/src/libostree/ostree-varint.c'; fi` + +tests/test_varint-test-varint.o: tests/test-varint.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_varint_CFLAGS) $(CFLAGS) -MT tests/test_varint-test-varint.o -MD -MP -MF tests/$(DEPDIR)/test_varint-test-varint.Tpo -c -o tests/test_varint-test-varint.o `test -f 'tests/test-varint.c' || echo '$(srcdir)/'`tests/test-varint.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_varint-test-varint.Tpo tests/$(DEPDIR)/test_varint-test-varint.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-varint.c' object='tests/test_varint-test-varint.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_varint_CFLAGS) $(CFLAGS) -c -o tests/test_varint-test-varint.o `test -f 'tests/test-varint.c' || echo '$(srcdir)/'`tests/test-varint.c + +tests/test_varint-test-varint.obj: tests/test-varint.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_varint_CFLAGS) $(CFLAGS) -MT tests/test_varint-test-varint.obj -MD -MP -MF tests/$(DEPDIR)/test_varint-test-varint.Tpo -c -o tests/test_varint-test-varint.obj `if test -f 'tests/test-varint.c'; then $(CYGPATH_W) 'tests/test-varint.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-varint.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) tests/$(DEPDIR)/test_varint-test-varint.Tpo tests/$(DEPDIR)/test_varint-test-varint.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tests/test-varint.c' object='tests/test_varint-test-varint.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_test_varint_CFLAGS) $(CFLAGS) -c -o tests/test_varint-test-varint.obj `if test -f 'tests/test-varint.c'; then $(CYGPATH_W) 'tests/test-varint.c'; else $(CYGPATH_W) '$(srcdir)/tests/test-varint.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf bsdiff/.libs bsdiff/_libs + -rm -rf libglnx/.libs libglnx/_libs + -rm -rf src/libostree/.libs src/libostree/_libs + -rm -rf src/libotutil/.libs src/libotutil/_libs + -rm -rf tests/.libs tests/_libs + +distclean-libtool: + -rm -f libtool config.lt +install-man1: $(man1_MANS) + @$(NORMAL_INSTALL) + @list1='$(man1_MANS)'; \ + list2=''; \ + test -n "$(man1dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.1[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) +install-man5: $(man5_MANS) + @$(NORMAL_INSTALL) + @list1='$(man5_MANS)'; \ + list2=''; \ + test -n "$(man5dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.5[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ + done; } + +uninstall-man5: + @$(NORMAL_UNINSTALL) + @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir) +install-dist_completionsDATA: $(dist_completions_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_completions_DATA)'; test -n "$(completionsdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(completionsdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(completionsdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(completionsdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(completionsdir)" || exit $$?; \ + done + +uninstall-dist_completionsDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_completions_DATA)'; test -n "$(completionsdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(completionsdir)'; $(am__uninstall_files_from_dir) +install-dist_gpginsttestDATA: $(dist_gpginsttest_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_gpginsttest_DATA)'; test -n "$(gpginsttestdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(gpginsttestdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(gpginsttestdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(gpginsttestdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(gpginsttestdir)" || exit $$?; \ + done + +uninstall-dist_gpginsttestDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_gpginsttest_DATA)'; test -n "$(gpginsttestdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(gpginsttestdir)'; $(am__uninstall_files_from_dir) +install-dist_gpginsttest_revocDATA: $(dist_gpginsttest_revoc_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_gpginsttest_revoc_DATA)'; test -n "$(gpginsttest_revocdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(gpginsttest_revocdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(gpginsttest_revocdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(gpginsttest_revocdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(gpginsttest_revocdir)" || exit $$?; \ + done + +uninstall-dist_gpginsttest_revocDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_gpginsttest_revoc_DATA)'; test -n "$(gpginsttest_revocdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(gpginsttest_revocdir)'; $(am__uninstall_files_from_dir) +install-dist_gpginsttest_trustedDATA: $(dist_gpginsttest_trusted_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_gpginsttest_trusted_DATA)'; test -n "$(gpginsttest_trusteddir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(gpginsttest_trusteddir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(gpginsttest_trusteddir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(gpginsttest_trusteddir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(gpginsttest_trusteddir)" || exit $$?; \ + done + +uninstall-dist_gpginsttest_trustedDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_gpginsttest_trusted_DATA)'; test -n "$(gpginsttest_trusteddir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(gpginsttest_trusteddir)'; $(am__uninstall_files_from_dir) +install-dist_gpgvinsttestDATA: $(dist_gpgvinsttest_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_gpgvinsttest_DATA)'; test -n "$(gpgvinsttestdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(gpgvinsttestdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(gpgvinsttestdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(gpgvinsttestdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(gpgvinsttestdir)" || exit $$?; \ + done + +uninstall-dist_gpgvinsttestDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_gpgvinsttest_DATA)'; test -n "$(gpgvinsttestdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(gpgvinsttestdir)'; $(am__uninstall_files_from_dir) +install-dist_systemdtmpfilesDATA: $(dist_systemdtmpfiles_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_systemdtmpfiles_DATA)'; test -n "$(systemdtmpfilesdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemdtmpfilesdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemdtmpfilesdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdtmpfilesdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdtmpfilesdir)" || exit $$?; \ + done + +uninstall-dist_systemdtmpfilesDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_systemdtmpfiles_DATA)'; test -n "$(systemdtmpfilesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(systemdtmpfilesdir)'; $(am__uninstall_files_from_dir) +install-dracutconfDATA: $(dracutconf_DATA) + @$(NORMAL_INSTALL) + @list='$(dracutconf_DATA)'; test -n "$(dracutconfdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dracutconfdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dracutconfdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dracutconfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(dracutconfdir)" || exit $$?; \ + done + +uninstall-dracutconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(dracutconf_DATA)'; test -n "$(dracutconfdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(dracutconfdir)'; $(am__uninstall_files_from_dir) +install-girDATA: $(gir_DATA) + @$(NORMAL_INSTALL) + @list='$(gir_DATA)'; test -n "$(girdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(girdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(girdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(girdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(girdir)" || exit $$?; \ + done + +uninstall-girDATA: + @$(NORMAL_UNINSTALL) + @list='$(gir_DATA)'; test -n "$(girdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(girdir)'; $(am__uninstall_files_from_dir) +install-gpgreadmeDATA: $(gpgreadme_DATA) + @$(NORMAL_INSTALL) + @list='$(gpgreadme_DATA)'; test -n "$(gpgreadmedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(gpgreadmedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(gpgreadmedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(gpgreadmedir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(gpgreadmedir)" || exit $$?; \ + done + +uninstall-gpgreadmeDATA: + @$(NORMAL_UNINSTALL) + @list='$(gpgreadme_DATA)'; test -n "$(gpgreadmedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(gpgreadmedir)'; $(am__uninstall_files_from_dir) +install-installed_testDATA: $(installed_test_DATA) + @$(NORMAL_INSTALL) + @list='$(installed_test_DATA)'; test -n "$(installed_testdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(installed_testdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(installed_testdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(installed_testdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(installed_testdir)" || exit $$?; \ + done + +uninstall-installed_testDATA: + @$(NORMAL_UNINSTALL) + @list='$(installed_test_DATA)'; test -n "$(installed_testdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(installed_testdir)'; $(am__uninstall_files_from_dir) +install-installed_test_metaDATA: $(installed_test_meta_DATA) + @$(NORMAL_INSTALL) + @list='$(installed_test_meta_DATA)'; test -n "$(installed_test_metadir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(installed_test_metadir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(installed_test_metadir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(installed_test_metadir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(installed_test_metadir)" || exit $$?; \ + done + +uninstall-installed_test_metaDATA: + @$(NORMAL_UNINSTALL) + @list='$(installed_test_meta_DATA)'; test -n "$(installed_test_metadir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(installed_test_metadir)'; $(am__uninstall_files_from_dir) +install-mkinitcpioconfDATA: $(mkinitcpioconf_DATA) + @$(NORMAL_INSTALL) + @list='$(mkinitcpioconf_DATA)'; test -n "$(mkinitcpioconfdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(mkinitcpioconfdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(mkinitcpioconfdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(mkinitcpioconfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(mkinitcpioconfdir)" || exit $$?; \ + done + +uninstall-mkinitcpioconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(mkinitcpioconf_DATA)'; test -n "$(mkinitcpioconfdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(mkinitcpioconfdir)'; $(am__uninstall_files_from_dir) +install-nobase_installed_testDATA: $(nobase_installed_test_DATA) + @$(NORMAL_INSTALL) + @list='$(nobase_installed_test_DATA)'; test -n "$(installed_testdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(installed_testdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(installed_testdir)" || exit 1; \ + fi; \ + $(am__nobase_list) | while read dir files; do \ + xfiles=; for file in $$files; do \ + if test -f "$$file"; then xfiles="$$xfiles $$file"; \ + else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ + test -z "$$xfiles" || { \ + test "x$$dir" = x. || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(installed_testdir)/$$dir'"; \ + $(MKDIR_P) "$(DESTDIR)$(installed_testdir)/$$dir"; }; \ + echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(installed_testdir)/$$dir'"; \ + $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(installed_testdir)/$$dir" || exit $$?; }; \ + done + +uninstall-nobase_installed_testDATA: + @$(NORMAL_UNINSTALL) + @list='$(nobase_installed_test_DATA)'; test -n "$(installed_testdir)" || list=; \ + $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ + dir='$(DESTDIR)$(installed_testdir)'; $(am__uninstall_files_from_dir) +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) +install-systemdsystemunitDATA: $(systemdsystemunit_DATA) + @$(NORMAL_INSTALL) + @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemunitdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemdsystemunitdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdsystemunitdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdsystemunitdir)" || exit $$?; \ + done + +uninstall-systemdsystemunitDATA: + @$(NORMAL_UNINSTALL) + @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(systemdsystemunitdir)'; $(am__uninstall_files_from_dir) +install-typelibDATA: $(typelib_DATA) + @$(NORMAL_INSTALL) + @list='$(typelib_DATA)'; test -n "$(typelibdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(typelibdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(typelibdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(typelibdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(typelibdir)" || exit $$?; \ + done + +uninstall-typelibDATA: + @$(NORMAL_UNINSTALL) + @list='$(typelib_DATA)'; test -n "$(typelibdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(typelibdir)'; $(am__uninstall_files_from_dir) +install-libostreeincludeHEADERS: $(libostreeinclude_HEADERS) + @$(NORMAL_INSTALL) + @list='$(libostreeinclude_HEADERS)'; test -n "$(libostreeincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(libostreeincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libostreeincludedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libostreeincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(libostreeincludedir)" || exit $$?; \ + done + +uninstall-libostreeincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(libostreeinclude_HEADERS)'; test -n "$(libostreeincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(libostreeincludedir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: $(check_PROGRAMS) $(check_LTLIBRARIES) $(check_SCRIPTS) $(check_DATA) + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all $(check_PROGRAMS) $(check_LTLIBRARIES) $(check_SCRIPTS) $(check_DATA) + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +tests/test-bloom.log: tests/test-bloom$(EXEEXT) + @p='tests/test-bloom$(EXEEXT)'; \ + b='tests/test-bloom'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-repo-finder-config.log: tests/test-repo-finder-config$(EXEEXT) + @p='tests/test-repo-finder-config$(EXEEXT)'; \ + b='tests/test-repo-finder-config'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-repo-finder-mount.log: tests/test-repo-finder-mount$(EXEEXT) + @p='tests/test-repo-finder-mount$(EXEEXT)'; \ + b='tests/test-repo-finder-mount'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-repo-finder-avahi.log: tests/test-repo-finder-avahi$(EXEEXT) + @p='tests/test-repo-finder-avahi$(EXEEXT)'; \ + b='tests/test-repo-finder-avahi'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-varint.log: tests/test-varint$(EXEEXT) + @p='tests/test-varint$(EXEEXT)'; \ + b='tests/test-varint'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-ot-unix-utils.log: tests/test-ot-unix-utils$(EXEEXT) + @p='tests/test-ot-unix-utils$(EXEEXT)'; \ + b='tests/test-ot-unix-utils'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-bsdiff.log: tests/test-bsdiff$(EXEEXT) + @p='tests/test-bsdiff$(EXEEXT)'; \ + b='tests/test-bsdiff'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-mutable-tree.log: tests/test-mutable-tree$(EXEEXT) + @p='tests/test-mutable-tree$(EXEEXT)'; \ + b='tests/test-mutable-tree'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-keyfile-utils.log: tests/test-keyfile-utils$(EXEEXT) + @p='tests/test-keyfile-utils$(EXEEXT)'; \ + b='tests/test-keyfile-utils'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-ot-opt-utils.log: tests/test-ot-opt-utils$(EXEEXT) + @p='tests/test-ot-opt-utils$(EXEEXT)'; \ + b='tests/test-ot-opt-utils'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-ot-tool-util.log: tests/test-ot-tool-util$(EXEEXT) + @p='tests/test-ot-tool-util$(EXEEXT)'; \ + b='tests/test-ot-tool-util'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-checksum.log: tests/test-checksum$(EXEEXT) + @p='tests/test-checksum$(EXEEXT)'; \ + b='tests/test-checksum'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-lzma.log: tests/test-lzma$(EXEEXT) + @p='tests/test-lzma$(EXEEXT)'; \ + b='tests/test-lzma'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-rollsum.log: tests/test-rollsum$(EXEEXT) + @p='tests/test-rollsum$(EXEEXT)'; \ + b='tests/test-rollsum'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-basic-c.log: tests/test-basic-c$(EXEEXT) + @p='tests/test-basic-c$(EXEEXT)'; \ + b='tests/test-basic-c'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-sysroot-c.log: tests/test-sysroot-c$(EXEEXT) + @p='tests/test-sysroot-c$(EXEEXT)'; \ + b='tests/test-sysroot-c'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-c.log: tests/test-pull-c$(EXEEXT) + @p='tests/test-pull-c$(EXEEXT)'; \ + b='tests/test-pull-c'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-repo.log: tests/test-repo$(EXEEXT) + @p='tests/test-repo$(EXEEXT)'; \ + b='tests/test-repo'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-include-ostree-h.log: tests/test-include-ostree-h$(EXEEXT) + @p='tests/test-include-ostree-h$(EXEEXT)'; \ + b='tests/test-include-ostree-h'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-kargs.log: tests/test-kargs$(EXEEXT) + @p='tests/test-kargs$(EXEEXT)'; \ + b='tests/test-kargs'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-gpg-verify-result.log: tests/test-gpg-verify-result$(EXEEXT) + @p='tests/test-gpg-verify-result$(EXEEXT)'; \ + b='tests/test-gpg-verify-result'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-libarchive-import.log: tests/test-libarchive-import$(EXEEXT) + @p='tests/test-libarchive-import$(EXEEXT)'; \ + b='tests/test-libarchive-import'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-basic.sh.log: tests/test-basic.sh + @p='tests/test-basic.sh'; \ + b='tests/test-basic.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-basic-user.sh.log: tests/test-basic-user.sh + @p='tests/test-basic-user.sh'; \ + b='tests/test-basic-user.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-basic-user-only.sh.log: tests/test-basic-user-only.sh + @p='tests/test-basic-user-only.sh'; \ + b='tests/test-basic-user-only.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-basic-root.sh.log: tests/test-basic-root.sh + @p='tests/test-basic-root.sh'; \ + b='tests/test-basic-root.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-subpath.sh.log: tests/test-pull-subpath.sh + @p='tests/test-pull-subpath.sh'; \ + b='tests/test-pull-subpath.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-archivez.sh.log: tests/test-archivez.sh + @p='tests/test-archivez.sh'; \ + b='tests/test-archivez.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-remote-add.sh.log: tests/test-remote-add.sh + @p='tests/test-remote-add.sh'; \ + b='tests/test-remote-add.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-remote-headers.sh.log: tests/test-remote-headers.sh + @p='tests/test-remote-headers.sh'; \ + b='tests/test-remote-headers.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-commit-sign.sh.log: tests/test-commit-sign.sh + @p='tests/test-commit-sign.sh'; \ + b='tests/test-commit-sign.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-export.sh.log: tests/test-export.sh + @p='tests/test-export.sh'; \ + b='tests/test-export.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-help.sh.log: tests/test-help.sh + @p='tests/test-help.sh'; \ + b='tests/test-help.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-libarchive.sh.log: tests/test-libarchive.sh + @p='tests/test-libarchive.sh'; \ + b='tests/test-libarchive.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-parent.sh.log: tests/test-parent.sh + @p='tests/test-parent.sh'; \ + b='tests/test-parent.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-bare.sh.log: tests/test-pull-bare.sh + @p='tests/test-pull-bare.sh'; \ + b='tests/test-pull-bare.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-bareuser.sh.log: tests/test-pull-bareuser.sh + @p='tests/test-pull-bareuser.sh'; \ + b='tests/test-pull-bareuser.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-bareuseronly.sh.log: tests/test-pull-bareuseronly.sh + @p='tests/test-pull-bareuseronly.sh'; \ + b='tests/test-pull-bareuseronly.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull2-bareuseronly.sh.log: tests/test-pull2-bareuseronly.sh + @p='tests/test-pull2-bareuseronly.sh'; \ + b='tests/test-pull2-bareuseronly.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-commit-only.sh.log: tests/test-pull-commit-only.sh + @p='tests/test-pull-commit-only.sh'; \ + b='tests/test-pull-commit-only.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-depth.sh.log: tests/test-pull-depth.sh + @p='tests/test-pull-depth.sh'; \ + b='tests/test-pull-depth.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-mirror-summary.sh.log: tests/test-pull-mirror-summary.sh + @p='tests/test-pull-mirror-summary.sh'; \ + b='tests/test-pull-mirror-summary.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-large-metadata.sh.log: tests/test-pull-large-metadata.sh + @p='tests/test-pull-large-metadata.sh'; \ + b='tests/test-pull-large-metadata.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-metalink.sh.log: tests/test-pull-metalink.sh + @p='tests/test-pull-metalink.sh'; \ + b='tests/test-pull-metalink.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-summary-sigs.sh.log: tests/test-pull-summary-sigs.sh + @p='tests/test-pull-summary-sigs.sh'; \ + b='tests/test-pull-summary-sigs.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-resume.sh.log: tests/test-pull-resume.sh + @p='tests/test-pull-resume.sh'; \ + b='tests/test-pull-resume.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-basicauth.sh.log: tests/test-pull-basicauth.sh + @p='tests/test-pull-basicauth.sh'; \ + b='tests/test-pull-basicauth.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-repeated.sh.log: tests/test-pull-repeated.sh + @p='tests/test-pull-repeated.sh'; \ + b='tests/test-pull-repeated.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-sizes.sh.log: tests/test-pull-sizes.sh + @p='tests/test-pull-sizes.sh'; \ + b='tests/test-pull-sizes.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-untrusted.sh.log: tests/test-pull-untrusted.sh + @p='tests/test-pull-untrusted.sh'; \ + b='tests/test-pull-untrusted.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-override-url.sh.log: tests/test-pull-override-url.sh + @p='tests/test-pull-override-url.sh'; \ + b='tests/test-pull-override-url.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-localcache.sh.log: tests/test-pull-localcache.sh + @p='tests/test-pull-localcache.sh'; \ + b='tests/test-pull-localcache.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-local-pull.sh.log: tests/test-local-pull.sh + @p='tests/test-local-pull.sh'; \ + b='tests/test-local-pull.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-local-pull-depth.sh.log: tests/test-local-pull-depth.sh + @p='tests/test-local-pull-depth.sh'; \ + b='tests/test-local-pull-depth.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-upgrade-unconfigured.sh.log: tests/test-admin-upgrade-unconfigured.sh + @p='tests/test-admin-upgrade-unconfigured.sh'; \ + b='tests/test-admin-upgrade-unconfigured.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-upgrade-endoflife.sh.log: tests/test-admin-upgrade-endoflife.sh + @p='tests/test-admin-upgrade-endoflife.sh'; \ + b='tests/test-admin-upgrade-endoflife.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-upgrade-systemd-update.sh.log: tests/test-admin-upgrade-systemd-update.sh + @p='tests/test-admin-upgrade-systemd-update.sh'; \ + b='tests/test-admin-upgrade-systemd-update.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-syslinux.sh.log: tests/test-admin-deploy-syslinux.sh + @p='tests/test-admin-deploy-syslinux.sh'; \ + b='tests/test-admin-deploy-syslinux.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-2.sh.log: tests/test-admin-deploy-2.sh + @p='tests/test-admin-deploy-2.sh'; \ + b='tests/test-admin-deploy-2.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-karg.sh.log: tests/test-admin-deploy-karg.sh + @p='tests/test-admin-deploy-karg.sh'; \ + b='tests/test-admin-deploy-karg.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-switch.sh.log: tests/test-admin-deploy-switch.sh + @p='tests/test-admin-deploy-switch.sh'; \ + b='tests/test-admin-deploy-switch.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-etcmerge-cornercases.sh.log: tests/test-admin-deploy-etcmerge-cornercases.sh + @p='tests/test-admin-deploy-etcmerge-cornercases.sh'; \ + b='tests/test-admin-deploy-etcmerge-cornercases.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-uboot.sh.log: tests/test-admin-deploy-uboot.sh + @p='tests/test-admin-deploy-uboot.sh'; \ + b='tests/test-admin-deploy-uboot.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-grub2.sh.log: tests/test-admin-deploy-grub2.sh + @p='tests/test-admin-deploy-grub2.sh'; \ + b='tests/test-admin-deploy-grub2.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-nomerge.sh.log: tests/test-admin-deploy-nomerge.sh + @p='tests/test-admin-deploy-nomerge.sh'; \ + b='tests/test-admin-deploy-nomerge.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-none.sh.log: tests/test-admin-deploy-none.sh + @p='tests/test-admin-deploy-none.sh'; \ + b='tests/test-admin-deploy-none.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-bootid-gc.sh.log: tests/test-admin-deploy-bootid-gc.sh + @p='tests/test-admin-deploy-bootid-gc.sh'; \ + b='tests/test-admin-deploy-bootid-gc.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-instutil-set-kargs.sh.log: tests/test-admin-instutil-set-kargs.sh + @p='tests/test-admin-instutil-set-kargs.sh'; \ + b='tests/test-admin-instutil-set-kargs.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-upgrade-not-backwards.sh.log: tests/test-admin-upgrade-not-backwards.sh + @p='tests/test-admin-upgrade-not-backwards.sh'; \ + b='tests/test-admin-upgrade-not-backwards.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-pull-deploy-commit.sh.log: tests/test-admin-pull-deploy-commit.sh + @p='tests/test-admin-pull-deploy-commit.sh'; \ + b='tests/test-admin-pull-deploy-commit.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-pull-deploy-split.sh.log: tests/test-admin-pull-deploy-split.sh + @p='tests/test-admin-pull-deploy-split.sh'; \ + b='tests/test-admin-pull-deploy-split.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-locking.sh.log: tests/test-admin-locking.sh + @p='tests/test-admin-locking.sh'; \ + b='tests/test-admin-locking.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-deploy-clean.sh.log: tests/test-admin-deploy-clean.sh + @p='tests/test-admin-deploy-clean.sh'; \ + b='tests/test-admin-deploy-clean.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-reset-nonlinear.sh.log: tests/test-reset-nonlinear.sh + @p='tests/test-reset-nonlinear.sh'; \ + b='tests/test-reset-nonlinear.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-oldstyle-partial.sh.log: tests/test-oldstyle-partial.sh + @p='tests/test-oldstyle-partial.sh'; \ + b='tests/test-oldstyle-partial.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-delta.sh.log: tests/test-delta.sh + @p='tests/test-delta.sh'; \ + b='tests/test-delta.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-xattrs.sh.log: tests/test-xattrs.sh + @p='tests/test-xattrs.sh'; \ + b='tests/test-xattrs.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-auto-summary.sh.log: tests/test-auto-summary.sh + @p='tests/test-auto-summary.sh'; \ + b='tests/test-auto-summary.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-prune.sh.log: tests/test-prune.sh + @p='tests/test-prune.sh'; \ + b='tests/test-prune.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-concurrency.py.log: tests/test-concurrency.py + @p='tests/test-concurrency.py'; \ + b='tests/test-concurrency.py'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-refs.sh.log: tests/test-refs.sh + @p='tests/test-refs.sh'; \ + b='tests/test-refs.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-demo-buildsystem.sh.log: tests/test-demo-buildsystem.sh + @p='tests/test-demo-buildsystem.sh'; \ + b='tests/test-demo-buildsystem.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-switchroot.sh.log: tests/test-switchroot.sh + @p='tests/test-switchroot.sh'; \ + b='tests/test-switchroot.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-contenturl.sh.log: tests/test-pull-contenturl.sh + @p='tests/test-pull-contenturl.sh'; \ + b='tests/test-pull-contenturl.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-mirrorlist.sh.log: tests/test-pull-mirrorlist.sh + @p='tests/test-pull-mirrorlist.sh'; \ + b='tests/test-pull-mirrorlist.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-summary-update.sh.log: tests/test-summary-update.sh + @p='tests/test-summary-update.sh'; \ + b='tests/test-summary-update.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-summary-view.sh.log: tests/test-summary-view.sh + @p='tests/test-summary-view.sh'; \ + b='tests/test-summary-view.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-no-initramfs.sh.log: tests/test-no-initramfs.sh + @p='tests/test-no-initramfs.sh'; \ + b='tests/test-no-initramfs.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-create-usb.sh.log: tests/test-create-usb.sh + @p='tests/test-create-usb.sh'; \ + b='tests/test-create-usb.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-find-remotes.sh.log: tests/test-find-remotes.sh + @p='tests/test-find-remotes.sh'; \ + b='tests/test-find-remotes.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-fsck-collections.sh.log: tests/test-fsck-collections.sh + @p='tests/test-fsck-collections.sh'; \ + b='tests/test-fsck-collections.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-fsck-delete.sh.log: tests/test-fsck-delete.sh + @p='tests/test-fsck-delete.sh'; \ + b='tests/test-fsck-delete.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-init-collections.sh.log: tests/test-init-collections.sh + @p='tests/test-init-collections.sh'; \ + b='tests/test-init-collections.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-prune-collections.sh.log: tests/test-prune-collections.sh + @p='tests/test-prune-collections.sh'; \ + b='tests/test-prune-collections.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-refs-collections.sh.log: tests/test-refs-collections.sh + @p='tests/test-refs-collections.sh'; \ + b='tests/test-refs-collections.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-remote-add-collections.sh.log: tests/test-remote-add-collections.sh + @p='tests/test-remote-add-collections.sh'; \ + b='tests/test-remote-add-collections.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-repo-finder-mount-integration.sh.log: tests/test-repo-finder-mount-integration.sh + @p='tests/test-repo-finder-mount-integration.sh'; \ + b='tests/test-repo-finder-mount-integration.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-summary-collections.sh.log: tests/test-summary-collections.sh + @p='tests/test-summary-collections.sh'; \ + b='tests/test-summary-collections.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-collections.sh.log: tests/test-pull-collections.sh + @p='tests/test-pull-collections.sh'; \ + b='tests/test-pull-collections.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-config.sh.log: tests/test-config.sh + @p='tests/test-config.sh'; \ + b='tests/test-config.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-signed-commit.sh.log: tests/test-signed-commit.sh + @p='tests/test-signed-commit.sh'; \ + b='tests/test-signed-commit.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-signed-pull.sh.log: tests/test-signed-pull.sh + @p='tests/test-signed-pull.sh'; \ + b='tests/test-signed-pull.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pre-signed-pull.sh.log: tests/test-pre-signed-pull.sh + @p='tests/test-pre-signed-pull.sh'; \ + b='tests/test-pre-signed-pull.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-signed-pull-summary.sh.log: tests/test-signed-pull-summary.sh + @p='tests/test-signed-pull-summary.sh'; \ + b='tests/test-signed-pull-summary.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-remote-gpg-import.sh.log: tests/test-remote-gpg-import.sh + @p='tests/test-remote-gpg-import.sh'; \ + b='tests/test-remote-gpg-import.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-gpg-signed-commit.sh.log: tests/test-gpg-signed-commit.sh + @p='tests/test-gpg-signed-commit.sh'; \ + b='tests/test-gpg-signed-commit.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-admin-gpg.sh.log: tests/test-admin-gpg.sh + @p='tests/test-admin-gpg.sh'; \ + b='tests/test-admin-gpg.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-rofiles-fuse.sh.log: tests/test-rofiles-fuse.sh + @p='tests/test-rofiles-fuse.sh'; \ + b='tests/test-rofiles-fuse.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-remote-cookies.sh.log: tests/test-remote-cookies.sh + @p='tests/test-remote-cookies.sh'; \ + b='tests/test-remote-cookies.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-corruption.sh.log: tests/test-corruption.sh + @p='tests/test-corruption.sh'; \ + b='tests/test-corruption.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-pull-corruption.sh.log: tests/test-pull-corruption.sh + @p='tests/test-pull-corruption.sh'; \ + b='tests/test-pull-corruption.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-core.js.log: tests/test-core.js + @p='tests/test-core.js'; \ + b='tests/test-core.js'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-remotes-config-dir.js.log: tests/test-remotes-config-dir.js + @p='tests/test-remotes-config-dir.js'; \ + b='tests/test-remotes-config-dir.js'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-sizes.js.log: tests/test-sizes.js + @p='tests/test-sizes.js'; \ + b='tests/test-sizes.js'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-sysroot.js.log: tests/test-sysroot.js + @p='tests/test-sysroot.js'; \ + b='tests/test-sysroot.js'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-symbols.sh.log: tests/test-symbols.sh + @p='tests/test-symbols.sh'; \ + b='tests/test-symbols.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/coccinelle.sh.log: tests/coccinelle.sh + @p='tests/coccinelle.sh'; \ + b='tests/coccinelle.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +test-libglnx-xattrs.log: test-libglnx-xattrs$(EXEEXT) + @p='test-libglnx-xattrs$(EXEEXT)'; \ + b='test-libglnx-xattrs'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +test-libglnx-fdio.log: test-libglnx-fdio$(EXEEXT) + @p='test-libglnx-fdio$(EXEEXT)'; \ + b='test-libglnx-fdio'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +test-libglnx-errors.log: test-libglnx-errors$(EXEEXT) + @p='test-libglnx-errors$(EXEEXT)'; \ + b='test-libglnx-errors'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +test-libglnx-macros.log: test-libglnx-macros$(EXEEXT) + @p='test-libglnx-macros$(EXEEXT)'; \ + b='test-libglnx-macros'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +test-libglnx-shutil.log: test-libglnx-shutil$(EXEEXT) + @p='test-libglnx-shutil$(EXEEXT)'; \ + b='test-libglnx-shutil'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) +@ENABLE_RUST_FALSE@dist-hook: + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@@ENABLE_RUST_FALSE@check-local: +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_LTLIBRARIES) \ + $(check_SCRIPTS) $(check_DATA) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS check-local +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-recursive +all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(SCRIPTS) $(MANS) $(DATA) \ + $(HEADERS) config.h all-local +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(systemdsystemgeneratordir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(privlibdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(dracutmoddir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(mkinitcpioinstalldir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(completionsdir)" "$(DESTDIR)$(gpginsttestdir)" "$(DESTDIR)$(gpginsttest_revocdir)" "$(DESTDIR)$(gpginsttest_trusteddir)" "$(DESTDIR)$(gpgvinsttestdir)" "$(DESTDIR)$(systemdtmpfilesdir)" "$(DESTDIR)$(dracutconfdir)" "$(DESTDIR)$(girdir)" "$(DESTDIR)$(gpgreadmedir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(installed_test_metadir)" "$(DESTDIR)$(mkinitcpioconfdir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(typelibdir)" "$(DESTDIR)$(libostreeincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f bsdiff/$(DEPDIR)/$(am__dirstamp) + -rm -f bsdiff/$(am__dirstamp) + -rm -f libglnx/$(DEPDIR)/$(am__dirstamp) + -rm -f libglnx/$(am__dirstamp) + -rm -f libglnx/tests/$(DEPDIR)/$(am__dirstamp) + -rm -f libglnx/tests/$(am__dirstamp) + -rm -f src/libostree/$(DEPDIR)/$(am__dirstamp) + -rm -f src/libostree/$(am__dirstamp) + -rm -f src/libotutil/$(DEPDIR)/$(am__dirstamp) + -rm -f src/libotutil/$(am__dirstamp) + -rm -f src/ostree/$(DEPDIR)/$(am__dirstamp) + -rm -f src/ostree/$(am__dirstamp) + -rm -f src/rofiles-fuse/$(DEPDIR)/$(am__dirstamp) + -rm -f src/rofiles-fuse/$(am__dirstamp) + -rm -f src/switchroot/$(DEPDIR)/$(am__dirstamp) + -rm -f src/switchroot/$(am__dirstamp) + -rm -f tests/$(DEPDIR)/$(am__dirstamp) + -rm -f tests/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +@ENABLE_RUST_FALSE@clean-local: +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-checkLTLIBRARIES clean-checkPROGRAMS \ + clean-generic clean-installed_testLTLIBRARIES \ + clean-installed_testPROGRAMS clean-libLTLIBRARIES \ + clean-libexecPROGRAMS clean-libtool clean-local \ + clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ + clean-ostree_bootPROGRAMS clean-pkglibexecPROGRAMS \ + clean-privlibLTLIBRARIES clean-sbinPROGRAMS \ + clean-systemdsystemgeneratorPROGRAMS mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Plo + -rm -f bsdiff/$(DEPDIR)/libbsdiff_la-bspatch.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-backports.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-console.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-dirfd.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-errors.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-fdio.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-local-alloc.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-lockfile.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-shutil.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-xattrs.Plo + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po + -rm -f src/libostree/$(DEPDIR)/bupsplit.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-async-progress.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bloom.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-grub2.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-syslinux.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-uboot.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-zipl.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-chain-input-stream.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-checksum-input-stream.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-cmdprivate.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-core.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-deployment.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-diff.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-dummy-enumtypes.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-curl.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-soup.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-uri.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-util.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verifier.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result-dummy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-kernel-args.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-libarchive-input-stream.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-linuxfsutil.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-common.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-compressor.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-decompressor.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-metalink.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-mutable-tree.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-ref.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-checkout.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-commit.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file-enumerator.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-config.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-mount.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-core.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-processing.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-traverse.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-deploy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-upgrader.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-tls-cert-interaction.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-varint.Plo + -rm -f src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Po + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-instream.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-fs-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-keyfile-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-utils.Plo + -rm -f src/ostree/$(DEPDIR)/ostree-main.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-dump.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-editor.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-main.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Po + -rm -f src/ostree/$(DEPDIR)/ostree-parse-datetime.Po + -rm -f src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Po + -rm -f src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Po + -rm -f src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Po + -rm -f src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Po + -rm -f src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Po + -rm -f tests/$(DEPDIR)/get_byte_order-get-byte-order.Po + -rm -f tests/$(DEPDIR)/libostreetest_la-libostreetest.Plo + -rm -f tests/$(DEPDIR)/libostreetest_la-test-mock-gio.Plo + -rm -f tests/$(DEPDIR)/libreaddir_rand_la-readdir-rand.Plo + -rm -f tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Po + -rm -f tests/$(DEPDIR)/test_basic_c-test-basic-c.Po + -rm -f tests/$(DEPDIR)/test_bloom-test-bloom.Po + -rm -f tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Po + -rm -f tests/$(DEPDIR)/test_checksum-test-checksum.Po + -rm -f tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Po + -rm -f tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Po + -rm -f tests/$(DEPDIR)/test_kargs-test-kargs.Po + -rm -f tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Po + -rm -f tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Po + -rm -f tests/$(DEPDIR)/test_lzma-test-lzma.Po + -rm -f tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Po + -rm -f tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Po + -rm -f tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Po + -rm -f tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Po + -rm -f tests/$(DEPDIR)/test_pull_c-test-pull-c.Po + -rm -f tests/$(DEPDIR)/test_repo-test-repo.Po + -rm -f tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Po + -rm -f tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Po + -rm -f tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Po + -rm -f tests/$(DEPDIR)/test_rollsum-test-rollsum.Po + -rm -f tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Po + -rm -f tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Po + -rm -f tests/$(DEPDIR)/test_varint-test-varint.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-dist_completionsDATA \ + install-dist_gpginsttestDATA \ + install-dist_gpginsttest_revocDATA \ + install-dist_gpginsttest_trustedDATA \ + install-dist_gpgvinsttestDATA install-dist_systemdtmpfilesDATA \ + install-dracutconfDATA install-dracutmodSCRIPTS \ + install-girDATA install-gpgreadmeDATA \ + install-installed_testDATA install-installed_testLTLIBRARIES \ + install-installed_testPROGRAMS install-installed_testSCRIPTS \ + install-installed_test_metaDATA \ + install-libostreeincludeHEADERS install-man \ + install-mkinitcpioconfDATA install-mkinitcpioinstallSCRIPTS \ + install-nobase_installed_testDATA install-ostree_bootPROGRAMS \ + install-ostree_bootSCRIPTS install-pkgconfigDATA \ + install-privlibLTLIBRARIES \ + install-systemdsystemgeneratorPROGRAMS \ + install-systemdsystemunitDATA install-typelibDATA + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-binSCRIPTS \ + install-libLTLIBRARIES install-libexecPROGRAMS \ + install-pkglibexecPROGRAMS install-pkglibexecSCRIPTS \ + install-sbinPROGRAMS + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: install-man1 install-man5 + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f bsdiff/$(DEPDIR)/libbsdiff_la-bsdiff.Plo + -rm -f bsdiff/$(DEPDIR)/libbsdiff_la-bspatch.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-backports.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-console.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-dirfd.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-errors.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-fdio.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-local-alloc.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-lockfile.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-shutil.Plo + -rm -f libglnx/$(DEPDIR)/la-glnx-xattrs.Plo + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_errors-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_errors-test-libglnx-errors.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_fdio-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_fdio-test-libglnx-fdio.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_macros-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_macros-test-libglnx-macros.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_shutil-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_shutil-test-libglnx-shutil.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-libglnx-testlib.Po + -rm -f libglnx/tests/$(DEPDIR)/test_libglnx_xattrs-test-libglnx-xattrs.Po + -rm -f src/libostree/$(DEPDIR)/bupsplit.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-async-progress.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bloom.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-grub2.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-syslinux.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-uboot.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader-zipl.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootloader.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-chain-input-stream.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-checksum-input-stream.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-cmdprivate.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-core.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-deployment.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-diff.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-dummy-enumtypes.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-enumtypes.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-curl.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-soup.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-uri.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-util.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verifier.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result-dummy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-kernel-args.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-libarchive-input-stream.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-linuxfsutil.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-common.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-compressor.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-decompressor.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-metalink.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-mutable-tree.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-ref.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-checkout.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-commit.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file-enumerator.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi-parser.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-avahi.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-config.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-mount.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder-override.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-finder.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-libarchive.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-prune.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull-verify.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-pull.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-refs.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation-analysis.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-compilation.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-core.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-static-delta-processing.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-traverse.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-rollsum.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sepolicy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-dummy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign-ed25519.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sign.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-form.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-soup-uri.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-cleanup.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-deploy.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot-upgrader.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-sysroot.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-tls-cert-interaction.Plo + -rm -f src/libostree/$(DEPDIR)/libostree_1_la-ostree-varint.Plo + -rm -f src/libostree/$(DEPDIR)/tests_test_bloom-ostree-bloom.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_checksum-ostree-core.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_checksum-ostree-varint.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_kargs-ostree-kernel-args.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-common.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-compressor.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_lzma-ostree-lzma-decompressor.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_repo_finder_avahi-ostree-repo-finder-avahi-parser.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_rollsum-ostree-rollsum.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_rollsum_cli-ostree-rollsum.Po + -rm -f src/libostree/$(DEPDIR)/tests_test_varint-ostree-varint.Po + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-instream.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-checksum-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-fs-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-keyfile-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-builder.Plo + -rm -f src/libotutil/$(DEPDIR)/libotutil_la-ot-variant-utils.Plo + -rm -f src/ostree/$(DEPDIR)/ostree-main.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-cleanup.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-deploy.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-diff.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-finalize-staged.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-init-fs.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-instutil.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-os-init.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-pin.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-set-origin.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-status.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-switch.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-undeploy.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-unlock.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-builtin-upgrade.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-functions.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-grub2-generate.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-selinux-ensure-labeled.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-admin-instutil-builtin-set-kargs.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-admin.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-cat.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-checkout.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-checksum.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-commit.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-config.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-create-usb.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-diff.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-export.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-find-remotes.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-fsck.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-gpg-sign.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-init.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-log.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-ls.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-prune.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-pull-local.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-pull.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-refs.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-remote.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-reset.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-rev-parse.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-show.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-sign.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-static-delta.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-summary.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-builtin-trivial-httpd.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-dump.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-editor.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-main.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add-cookie.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-add.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete-cookie.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-delete.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-gpg-import.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list-cookies.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-list.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-refs.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-show-url.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-builtin-summary.Po + -rm -f src/ostree/$(DEPDIR)/ostree-ot-remote-cookie-util.Po + -rm -f src/ostree/$(DEPDIR)/ostree-parse-datetime.Po + -rm -f src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Po + -rm -f src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Po + -rm -f src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Po + -rm -f src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Po + -rm -f src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Po + -rm -f tests/$(DEPDIR)/get_byte_order-get-byte-order.Po + -rm -f tests/$(DEPDIR)/libostreetest_la-libostreetest.Plo + -rm -f tests/$(DEPDIR)/libostreetest_la-test-mock-gio.Plo + -rm -f tests/$(DEPDIR)/libreaddir_rand_la-readdir-rand.Plo + -rm -f tests/$(DEPDIR)/repo_finder_mount-repo-finder-mount.Po + -rm -f tests/$(DEPDIR)/test_basic_c-test-basic-c.Po + -rm -f tests/$(DEPDIR)/test_bloom-test-bloom.Po + -rm -f tests/$(DEPDIR)/test_bsdiff-test-bsdiff.Po + -rm -f tests/$(DEPDIR)/test_checksum-test-checksum.Po + -rm -f tests/$(DEPDIR)/test_gpg_verify_result-test-gpg-verify-result.Po + -rm -f tests/$(DEPDIR)/test_include_ostree_h-test-include-ostree-h.Po + -rm -f tests/$(DEPDIR)/test_kargs-test-kargs.Po + -rm -f tests/$(DEPDIR)/test_keyfile_utils-test-keyfile-utils.Po + -rm -f tests/$(DEPDIR)/test_libarchive_import-test-libarchive-import.Po + -rm -f tests/$(DEPDIR)/test_lzma-test-lzma.Po + -rm -f tests/$(DEPDIR)/test_mutable_tree-test-mutable-tree.Po + -rm -f tests/$(DEPDIR)/test_ot_opt_utils-test-ot-opt-utils.Po + -rm -f tests/$(DEPDIR)/test_ot_tool_util-test-ot-tool-util.Po + -rm -f tests/$(DEPDIR)/test_ot_unix_utils-test-ot-unix-utils.Po + -rm -f tests/$(DEPDIR)/test_pull_c-test-pull-c.Po + -rm -f tests/$(DEPDIR)/test_repo-test-repo.Po + -rm -f tests/$(DEPDIR)/test_repo_finder_avahi-test-repo-finder-avahi.Po + -rm -f tests/$(DEPDIR)/test_repo_finder_config-test-repo-finder-config.Po + -rm -f tests/$(DEPDIR)/test_repo_finder_mount-test-repo-finder-mount.Po + -rm -f tests/$(DEPDIR)/test_rollsum-test-rollsum.Po + -rm -f tests/$(DEPDIR)/test_rollsum_cli-test-rollsum-cli.Po + -rm -f tests/$(DEPDIR)/test_sysroot_c-test-sysroot-c.Po + -rm -f tests/$(DEPDIR)/test_varint-test-varint.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-dist_completionsDATA uninstall-dist_gpginsttestDATA \ + uninstall-dist_gpginsttest_revocDATA \ + uninstall-dist_gpginsttest_trustedDATA \ + uninstall-dist_gpgvinsttestDATA \ + uninstall-dist_systemdtmpfilesDATA uninstall-dracutconfDATA \ + uninstall-dracutmodSCRIPTS uninstall-girDATA \ + uninstall-gpgreadmeDATA uninstall-installed_testDATA \ + uninstall-installed_testLTLIBRARIES \ + uninstall-installed_testPROGRAMS \ + uninstall-installed_testSCRIPTS \ + uninstall-installed_test_metaDATA uninstall-libLTLIBRARIES \ + uninstall-libexecPROGRAMS uninstall-libostreeincludeHEADERS \ + uninstall-man uninstall-mkinitcpioconfDATA \ + uninstall-mkinitcpioinstallSCRIPTS \ + uninstall-nobase_installed_testDATA \ + uninstall-ostree_bootPROGRAMS uninstall-ostree_bootSCRIPTS \ + uninstall-pkgconfigDATA uninstall-pkglibexecPROGRAMS \ + uninstall-pkglibexecSCRIPTS uninstall-privlibLTLIBRARIES \ + uninstall-sbinPROGRAMS \ + uninstall-systemdsystemgeneratorPROGRAMS \ + uninstall-systemdsystemunitDATA uninstall-typelibDATA + +uninstall-man: uninstall-man1 uninstall-man5 + +.MAKE: $(am__recursive_targets) all check check-am install install-am \ + install-data-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ + am--depfiles am--refresh check check-TESTS check-am \ + check-local clean clean-binPROGRAMS clean-checkLTLIBRARIES \ + clean-checkPROGRAMS clean-cscope clean-generic \ + clean-installed_testLTLIBRARIES clean-installed_testPROGRAMS \ + clean-libLTLIBRARIES clean-libexecPROGRAMS clean-libtool \ + clean-local clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ + clean-ostree_bootPROGRAMS clean-pkglibexecPROGRAMS \ + clean-privlibLTLIBRARIES clean-sbinPROGRAMS \ + clean-systemdsystemgeneratorPROGRAMS cscope cscopelist-am \ + ctags ctags-am dist dist-all dist-bzip2 dist-gzip dist-hook \ + dist-lzip dist-shar dist-tarZ dist-xz dist-zip distcheck \ + distclean distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-binSCRIPTS \ + install-data install-data-am install-data-hook \ + install-dist_completionsDATA install-dist_gpginsttestDATA \ + install-dist_gpginsttest_revocDATA \ + install-dist_gpginsttest_trustedDATA \ + install-dist_gpgvinsttestDATA install-dist_systemdtmpfilesDATA \ + install-dracutconfDATA install-dracutmodSCRIPTS install-dvi \ + install-dvi-am install-exec install-exec-am install-girDATA \ + install-gpgreadmeDATA install-html install-html-am \ + install-info install-info-am install-installed_testDATA \ + install-installed_testLTLIBRARIES \ + install-installed_testPROGRAMS install-installed_testSCRIPTS \ + install-installed_test_metaDATA install-libLTLIBRARIES \ + install-libexecPROGRAMS install-libostreeincludeHEADERS \ + install-man install-man1 install-man5 \ + install-mkinitcpioconfDATA install-mkinitcpioinstallSCRIPTS \ + install-nobase_installed_testDATA install-ostree_bootPROGRAMS \ + install-ostree_bootSCRIPTS install-pdf install-pdf-am \ + install-pkgconfigDATA install-pkglibexecPROGRAMS \ + install-pkglibexecSCRIPTS install-privlibLTLIBRARIES \ + install-ps install-ps-am install-sbinPROGRAMS install-strip \ + install-systemdsystemgeneratorPROGRAMS \ + install-systemdsystemunitDATA install-typelibDATA installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + recheck tags tags-am uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-binSCRIPTS \ + uninstall-dist_completionsDATA uninstall-dist_gpginsttestDATA \ + uninstall-dist_gpginsttest_revocDATA \ + uninstall-dist_gpginsttest_trustedDATA \ + uninstall-dist_gpgvinsttestDATA \ + uninstall-dist_systemdtmpfilesDATA uninstall-dracutconfDATA \ + uninstall-dracutmodSCRIPTS uninstall-girDATA \ + uninstall-gpgreadmeDATA uninstall-installed_testDATA \ + uninstall-installed_testLTLIBRARIES \ + uninstall-installed_testPROGRAMS \ + uninstall-installed_testSCRIPTS \ + uninstall-installed_test_metaDATA uninstall-libLTLIBRARIES \ + uninstall-libexecPROGRAMS uninstall-libostreeincludeHEADERS \ + uninstall-man uninstall-man1 uninstall-man5 \ + uninstall-mkinitcpioconfDATA \ + uninstall-mkinitcpioinstallSCRIPTS \ + uninstall-nobase_installed_testDATA \ + uninstall-ostree_bootPROGRAMS uninstall-ostree_bootSCRIPTS \ + uninstall-pkgconfigDATA uninstall-pkglibexecPROGRAMS \ + uninstall-pkglibexecSCRIPTS uninstall-privlibLTLIBRARIES \ + uninstall-sbinPROGRAMS \ + uninstall-systemdsystemgeneratorPROGRAMS \ + uninstall-systemdsystemunitDATA uninstall-typelibDATA + +.PRECIOUS: Makefile + + +@ENABLE_INSTALLED_TESTS_TRUE@%.test: %$(EXEEXT) Makefile +@ENABLE_INSTALLED_TESTS_TRUE@ @$(MKDIR_P) $(dir $@) +@ENABLE_INSTALLED_TESTS_TRUE@ $(AM_V_GEN) (echo '[Test]' > $@.tmp; \ +@ENABLE_INSTALLED_TESTS_TRUE@ echo 'Type=session' >> $@.tmp; \ +@ENABLE_INSTALLED_TESTS_TRUE@ echo 'Exec=env G_TEST_SRCDIR=$(installed_testdir) G_TEST_BUILDDIR=$(installed_testdir) $(installed_testdir)/$(notdir $<)' >> $@.tmp; \ +@ENABLE_INSTALLED_TESTS_TRUE@ mv $@.tmp $@) +install-data-hook: $(INSTALL_DATA_HOOKS) +all-local: $(ALL_LOCAL_RULES) + +@BUILDOPT_INTROSPECTION_TRUE@include $(INTROSPECTION_MAKEFILE) + +@ENABLE_RUST_TRUE@check-local: +@ENABLE_RUST_TRUE@ cd $(srcdir)/rust && CARGO_TARGET_DIR=$(abs_top_builddir)/target cargo test + +@ENABLE_RUST_TRUE@clean-local: +@ENABLE_RUST_TRUE@ cd $(srcdir)/rust && CARGO_TARGET_DIR=$(abs_top_builddir)/target cargo clean + +@ENABLE_RUST_TRUE@dist-hook: +@ENABLE_RUST_TRUE@ (cd $(distdir)/rust && \ +@ENABLE_RUST_TRUE@ cp $(abs_top_srcdir)/rust/Cargo.lock . && \ +@ENABLE_RUST_TRUE@ cargo vendor -q && \ +@ENABLE_RUST_TRUE@ mkdir .cargo && \ +@ENABLE_RUST_TRUE@ cp cargo-vendor-config .cargo/config) +# See also autogen.sh and https://github.com/ostreedev/ostree/pull/1274/ +# +# v2017.12 didn't include test-libglnx-shutil.c, but if you re-run +# autogen.sh (as we do in Debian, to update the Autotools build system) +# it will try to build it. +$(srcdir)/libglnx/Makefile-libglnx.am.inc: $(srcdir)/libglnx/Makefile-libglnx.am + sed -e 's,$$(libglnx_srcpath),libglnx,g' < $< > $@ +# See the comment for the similar libglnx bit above +$(srcdir)/bsdiff/Makefile-bsdiff.am.inc: $(srcdir)/bsdiff/Makefile-bsdiff.am + sed -e 's,$$(libbsdiff_srcpath),bsdiff,g' < $< > $@ +@ENABLE_RUST_TRUE@$(bupsplitpath): Makefile $(BUPSPLIT_RUST_SRCS) +@ENABLE_RUST_TRUE@ cd $(top_srcdir)/rust && CARGO_TARGET_DIR=@abs_top_builddir@/target cargo build --verbose $(CARGO_RELEASE_ARGS) + +# TODO: GLIB_CHECK_VERSION > 2.5x: use --output instead of mv (see https://github.com/ostreedev/ostree/pull/1329) +src/libostree/ostree-enumtypes.h: src/libostree/ostree-enumtypes.h.template $(ENUM_TYPES) + $(AM_V_GEN) $(GLIB_MKENUMS) \ + --template $< \ + $(ENUM_TYPES) > $@.tmp && mv $@.tmp $@ + +src/libostree/ostree-enumtypes.c: src/libostree/ostree-enumtypes.c.template src/libostree/ostree-enumtypes.h $(ENUM_TYPES) + $(AM_V_GEN) $(GLIB_MKENUMS) \ + --template $< \ + $(ENUM_TYPES) > $@.tmp && mv $@.tmp $@ + +@BUILDOPT_INTROSPECTION_TRUE@OSTree-1.0.gir: libostree-1.la Makefile + +install-mkdir-remotes-d-hook: + mkdir -p $(DESTDIR)$(sysconfdir)/ostree/remotes.d + +src/ostree/parse-datetime.c: src/ostree/parse-datetime.y Makefile + mkdir -p src/ostree/ + $(AM_V_GEN) $(YACC) $< -o $@ + +@BUILDOPT_USE_STATIC_COMPILER_TRUE@ostree-prepare-root : $(ostree_prepare_root_SOURCES) +@BUILDOPT_USE_STATIC_COMPILER_TRUE@ $(STATIC_COMPILER) -o $@ -static $(top_srcdir)/src/switchroot/ostree-prepare-root.c $(ostree_prepare_root_CPPFLAGS) $(AM_CFLAGS) $(DEFAULT_INCLUDES) -DOSTREE_PREPARE_ROOT_STATIC=1 + +tests/libreaddir-rand.so: Makefile + mkdir -p tests/ + $(AM_V_GEN) ln -fns ../.libs/libreaddir-rand.so tests/ + +tests/%-symlink-stamp: % Makefile + $(AM_V_GEN) set -e; \ + lt_bin=`cd $(top_builddir) && ./libtool --mode=execute echo $*`; \ + if test "$${lt_bin}" = "$*"; then \ + real_bin=$(abs_top_builddir)/$*; \ + else \ + real_bin="$${lt_bin}"; \ + fi; \ + ln -sf "$${real_bin}" tests/$*; \ + touch $@ +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@check-local: +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@ echo "NOTE: Exclusive installed tests are enabled; to run them, make install, then: gnome-desktop-testing-runner -p 0 libostree/" + +@USE_LIBSOUP_FALSE@no-soup-for-you-warning: +@USE_LIBSOUP_FALSE@ @echo "WARNING: $(PACKAGE) was built without libsoup, which is currently" 1>&2 +@USE_LIBSOUP_FALSE@ @echo "WARNING: required for many unit tests." 1>&2 +@USE_LIBSOUP_FALSE@ sleep 10 +@USE_LIBSOUP_FALSE@check: no-soup-for-you-warning + +# Unfortunately the glib test data APIs don't actually handle +# non-recursive Automake, so we change our code to canonically look +# for tests/ which is just a symlink when installed. +@ENABLE_INSTALLED_TESTS_TRUE@install-installed-tests-extra: +@ENABLE_INSTALLED_TESTS_TRUE@ if test -L $(DESTDIR)$(installed_testdir)/tests; then \ +@ENABLE_INSTALLED_TESTS_TRUE@ rm $(DESTDIR)$(installed_testdir)/tests; \ +@ENABLE_INSTALLED_TESTS_TRUE@ fi +@ENABLE_INSTALLED_TESTS_TRUE@ ln -s . $(DESTDIR)$(installed_testdir)/tests +@BUILDOPT_ASAN_TRUE@@ENABLE_INSTALLED_TESTS_TRUE@ sed -e 's,^BUILT_WITH_ASAN=.*,BUILT_WITH_ASAN=1,' < $(srcdir)/tests/libtest.sh > $(DESTDIR)$(installed_testdir)/tests/libtest.sh +@BUILDOPT_ASAN_FALSE@@ENABLE_INSTALLED_TESTS_TRUE@ install -m 0644 $(srcdir)/tests/libtest.sh $(DESTDIR)$(installed_testdir)/tests/libtest.sh + +# Just forward these +build-kola-tests: + $(MAKE) -C tests/kola + +install-kola-tests: + $(MAKE) -C tests/kola install +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@install-grub2-config-hook: +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@ mkdir -p $(DESTDIR)$(grub2configdir) +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@ ln -sf $(pkglibexecdir)/grub2-15_ostree $(DESTDIR)$(grub2configdir)/15_ostree + +@ENABLE_MAN_TRUE@%.1: %.xml +@ENABLE_MAN_TRUE@ $(AM_V_GEN) $(XSLTPROC_MAN) --output $@ $(XSLT_STYLESHEET) $< + +@ENABLE_MAN_TRUE@%.5: %.xml +@ENABLE_MAN_TRUE@ $(AM_V_GEN) $(XSLTPROC_MAN) --output $@ $(XSLT_STYLESHEET) $< + +release-tag: + cd $(srcdir) && git $(srcdir) tag -m "Release $(VERSION)" v$(VERSION) + +release-tarball-embedded: + set -x; \ + GITVERSION=$(git_version_rpm); export GITVERSION; \ + TARFILE_TMP=ostree-embeddeps-$${GITVERSION}.tar.tmp; \ + REV=$$(git rev-parse HEAD); \ + echo "Archiving ostree at $${REV}"; \ + (cd $(srcdir); git archive --format=tar --prefix=ostree-embeddeps-$${GITVERSION}/ $${REV}) > $${TARFILE_TMP}; \ + (cd $$(git rev-parse --show-toplevel); git submodule status) | while read line; do \ + rev=$$(echo $$line | cut -f 1 -d ' '); path=$$(echo $$line | cut -f 2 -d ' '); \ + echo "Archiving $${path} at $${rev}"; \ + (cd $(srcdir)/$$path; git archive --format=tar --prefix=ostree-embeddeps-$${GITVERSION}/$$path/ $${rev}) > submodule.tar; \ + tar -A -f $${TARFILE_TMP} submodule.tar; \ + rm submodule.tar; \ + done; \ + echo "Archiving glib"; \ + $(embed_dependency) embedded-dependencies/glib; \ + echo "Archiving libsoup"; \ + $(embed_dependency) embedded-dependencies/libsoup; \ + mv ostree-embeddeps-$${GITVERSION}.tar{.tmp,}; \ + gzip -f ostree-embeddeps-$${GITVERSION}.tar + +# `make dist` + `make`; explicitly not the other +# parts of distcheck like `make uninstall` since +# we don't care about that. +dist-then-build: dist + rm $(distdir) -rf && tar -xf $(distdir).tar.xz + cd $(distdir) && mkdir _build && cd _build && \ + ../configure --prefix=/usr --libdir=/usr/lib --sysconfdir=/etc && \ + $(MAKE) && make install DESTDIR=$$(pwd)/_install && \ + rm -rf $(distdir) + +-include $(top_srcdir)/git.mk + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/README.md b/README.md new file mode 100644 index 0000000..1ef8e30 --- /dev/null +++ b/README.md @@ -0,0 +1,164 @@ +libostree +--------- + +New! See the docs online at [Read The Docs (OSTree)](https://ostree.readthedocs.org/en/latest/ ) + +----- + +This project is now known as "libostree", though it is still appropriate to use +the previous name: "OSTree" (or "ostree"). The focus is on projects which use +libostree's shared library, rather than users directly invoking the command line +tools (except for build systems). However, in most of the rest of the +documentation, we will use the term "OSTree", since it's slightly shorter, and +changing all documentation at once is impractical. We expect to transition to +the new name over time. + +As implied above, libostree is both a shared library and suite of command line +tools that combines a "git-like" model for committing and downloading bootable +filesystem trees, along with a layer for deploying them and managing the +bootloader configuration. + +The core OSTree model is like git in that it checksums individual files and has +a content-addressed-object store. It's unlike git in that it "checks out" the +files via hardlinks, and they thus need to be immutable to prevent corruption. +Therefore, another way to think of OSTree is that it's just a more polished +version of +[Linux VServer hardlinks](http://linux-vserver.org/index.php?title=util-vserver:Vhashify&oldid=2285). + +**Features:** + + - Transactional upgrades and rollback for the system + - Replicating content incrementally over HTTP via GPG signatures and "pinned TLS" support + - Support for parallel installing more than just 2 bootable roots + - Binary history on the server side (and client) + - Introspectable shared library API for build and deployment systems + - Flexible support for multiple branches and repositories, supporting + projects like [flatpak](https://github.com/flatpak/flatpak) which + use libostree for applications, rather than hosts. + +Operating systems and distributions using OSTree +--------------------- + +[Endless OS](https://endlessos.com/) uses libostree for their host system as +well as flatpak. See +their [eos-updater](https://github.com/endlessm/eos-updater) +and [deb-ostree-builder](https://github.com/dbnicholson/deb-ostree-builder) +projects. + +Fedora derivatives use rpm-ostree (noted below); there are 3 variants using OSTree: + + - [Fedora CoreOS](https://getfedora.org/en/coreos/) + - [Fedora Silverblue](https://silverblue.fedoraproject.org/) + - [Fedora IoT](https://iot.fedoraproject.org/) + +Red Hat Enterprise Linux CoreOS is a derivative of Fedora CoreOS, used in [OpenShift 4](https://try.openshift.com/). +The [machine-config-operator](https://github.com/openshift/machine-config-operator/blob/master/docs/OSUpgrades.md) +manages upgrades. RHEL CoreOS is also the successor to RHEL Atomic Host, which +uses rpm-ostree as well. + +[GNOME Continuous](https://wiki.gnome.org/Projects/GnomeContinuous) is +where OSTree was born - as a high performance continuous delivery/testing +system for GNOME. + +[Liri OS](https://liri.io/download/silverblue/) has the option to install +their distribution using ostree. + +Distribution build tools +------------------------ + +[meta-updater](https://github.com/advancedtelematic/meta-updater) is +a layer available for [OpenEmbedded](http://www.openembedded.org/wiki/Main_Page) +systems. + +[QtOTA](http://doc.qt.io/QtOTA/) is Qt's over-the-air update framework +which uses libostree. + +The [BuildStream](https://gitlab.com/BuildStream/buildstream) build and +integration tool supports importing and exporting from libostree repos. + +Fedora [coreos-assembler](https://github.com/coreos/coreos-assembler) is +the build tool used to generate Fedora CoreOS derivatives. + +Projects linking to libostree +----------------------------- + +[rpm-ostree](https://github.com/projectatomic/rpm-ostree) is used by the +Fedora-derived operating systems listed above. It is a full hybrid +image/package system. By default it uses libostree to atomically replicate a base OS +(all dependency resolution is done on the server), but it supports "package layering", where +additional RPMs can be layered on top of the base. This brings a "best of both worlds"" +model for image and package systems. + +[eos-updater](https://github.com/endlessm/eos-updater) is a daemon that implements updates +on EndlessOS. + +[flatpak](https://github.com/flatpak/flatpak) uses libostree for desktop +application containers. Unlike most of the other systems here, flatpak does not +use the "libostree host system" aspects (e.g. bootloader management), just the +"git-like hardlink dedup". For example, flatpak supports a per-user OSTree +repository. + +Language bindings +---- + +libostree is accessible via [GObject Introspection](https://gi.readthedocs.io/en/latest/); +any language which has implemented the GI binding model should work. +For example, Both [pygobject](https://pygobject.readthedocs.io/en/latest/) +and [gjs](https://gitlab.gnome.org/GNOME/gjs) are known to work +and further are actually used in libostree's test suite today. + +Some bindings take the approach of using GI as a lower level and +write higher level manual bindings on top; this is more common +for statically compiled languages. Here's a list of such bindings: + + - [ostree-go](https://github.com/ostreedev/ostree-go/) + - [ostree-rs](https://gitlab.com/fkrull/ostree-rs/) + +Building +-------- + +Releases are available as GPG signed git tags, and most recent +versions support extended validation using +[git-evtag](https://github.com/cgwalters/git-evtag). + +However, in order to build from a git clone, you must update the +submodules. If you're packaging OSTree and want a tarball, I +recommend using a "recursive git archive" script. There are several +available online; +[this code](https://github.com/ostreedev/ostree/blob/master/packaging/Makefile.dist-packaging#L11) +in OSTree is an example. + +Once you have a git clone or recursive archive, building is the +same as almost every autotools project: + +``` +git submodule update --init +env NOCONFIGURE=1 ./autogen.sh +./configure --prefix=... +make +make install DESTDIR=/path/to/dest +``` + +More documentation +------------------ + +New! See the docs online at [Read The Docs (OSTree)](https://ostree.readthedocs.org/en/latest/ ) + +Contributing +------------ + +See [Contributing](docs/CONTRIBUTING.md). + + +Licensing +------- + +The licensing for the *code* of libostree can be canonically found in the individual files; +and the overall status in the [COPYING](https://github.com/ostreedev/ostree/blob/master/COPYING) +file in the source. Currently, that's LGPLv2+. This also covers the man pages and API docs. + +The license for the manual documentation in the `doc/` directory is: +`SPDX-License-Identifier: (CC-BY-SA-3.0 OR GFDL-1.3-or-later)` +This is intended to allow use by Wikipedia and other projects. + +In general, files should have a `SPDX-License-Identifier` and that is canonical. diff --git a/TODO b/TODO new file mode 100644 index 0000000..5292ed4 --- /dev/null +++ b/TODO @@ -0,0 +1,46 @@ +* Documentation + - More gtk-doc + +* Local metadata packs + - Just to avoid lots of little files on each client + +* Hybrid SSL pull (fetch refs over SSL, content via plain HTTP) + +* ostree-commit: multithreaded/async (basically compute sha256 in parallel) + - Also speed up devino cache by having a big mmappable file that maps from + (device, inode) -> checksum. We need to keep the cache up to date; + investigate something like http://www.sqlite.org/wal.html for having + a shared file. + +* https://bugzilla.gnome.org/show_bug.cgi?id=721799 + https://mail.gnome.org/archives/ostree-list/2013-July/msg00005.html + Efficient delta format between commit objects, somewhat like + Chromium autoupdate: set of operations to perform given previous + object set to create new objects. + +* Flexible "prune" that allows keeping only a rolling subset of history. + For example, keep the last week, keep at least 1 build a week up + till a year ago, then 1 build a month, etc. Optionally rewrite commit + parent history? + +* Tests of corrupted repositories, more error conditions + +* Structured output from commandline? ostree --output={table,gvariant} ? + +* Better output on a tty - progress bars + Needs size metadata; see https://bugzilla.gnome.org/show_bug.cgi?id=709050 + https://bugzilla.gnome.org/show_bug.cgi?id=721799 + +* Do HTTP requests as unprivileged user (particularly before we've + done GPG verification) + https://bugzilla.gnome.org/show_bug.cgi?id=730037 + +* Reintroduce "ostree admin install": Could pull in host data, + such as uids and /etc/fstab. + +* Possibly move all of the "regular" commands to be "ostree repo" ? Then + we'd have: "ostree repo pull", "ostree repo ls", etc. + +* Multiple backends (BTRFS, etc.) + +* PackageKit backend diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..26d18fb --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,2242 @@ +# generated automatically by aclocal 1.16.1 -*- Autoconf -*- + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# Configure paths for GLIB +# Owen Taylor 1997-2001 + +# Increment this whenever this file is changed. +#serial 3 + +dnl AM_PATH_GLIB_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) +dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if gmodule, gobject, +dnl gthread, or gio is specified in MODULES, pass to pkg-config +dnl +AC_DEFUN([AM_PATH_GLIB_2_0], +[dnl +dnl Get the cflags and libraries from pkg-config +dnl + +dnl We can't use PKG_PREREQ because that needs 0.29. +m4_ifndef([PKG_PROG_PKG_CONFIG], + [pkg.m4 version 0.28 or later is required]) + +AC_ARG_ENABLE(glibtest, [ --disable-glibtest do not try to compile and run a test GLIB program], + , enable_glibtest=yes) + + min_glib_version=ifelse([$1], [], [2.0.0], [$1]) + pkg_config_args="glib-2.0 >= $min_glib_version" + for module in . $4 + do + case "$module" in + gmodule) + pkg_config_args="$pkg_config_args gmodule-2.0" + ;; + gmodule-no-export) + pkg_config_args="$pkg_config_args gmodule-no-export-2.0" + ;; + gobject) + pkg_config_args="$pkg_config_args gobject-2.0" + ;; + gthread) + pkg_config_args="$pkg_config_args gthread-2.0" + ;; + gio*) + pkg_config_args="$pkg_config_args $module-2.0" + ;; + esac + done + + PKG_PROG_PKG_CONFIG([0.16]) + + no_glib="" + + if test "x$PKG_CONFIG" = x ; then + no_glib=yes + PKG_CONFIG=no + fi + + dnl For GLIB_CFLAGS and GLIB_LIBS + PKG_CHECK_MODULES([GLIB], [$pkg_config_args], [:], [:]) + + dnl For the tools + PKG_CHECK_VAR([GLIB_GENMARSHAL], [glib-2.0], [glib_genmarshal]) + PKG_CHECK_VAR([GOBJECT_QUERY], [glib-2.0], [gobject_query]) + PKG_CHECK_VAR([GLIB_MKENUMS], [glib-2.0], [glib_mkenums]) + PKG_CHECK_VAR([GLIB_COMPILE_RESOURCES], [gio-2.0], [glib_compile_resources]) + + AC_MSG_CHECKING(for GLIB - version >= $min_glib_version) + + if test x$PKG_CONFIG != xno ; then + ## don't try to run the test against uninstalled libtool libs + if $PKG_CONFIG --uninstalled $pkg_config_args; then + echo "Will use uninstalled version of GLib found in PKG_CONFIG_PATH" + enable_glibtest=no + fi + + if $PKG_CONFIG --atleast-version $min_glib_version $pkg_config_args; then + : + else + no_glib=yes + fi + fi + + if test x"$no_glib" = x ; then + glib_config_major_version=`$PKG_CONFIG --modversion glib-2.0 | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + glib_config_minor_version=`$PKG_CONFIG --modversion glib-2.0 | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + glib_config_micro_version=`$PKG_CONFIG --modversion glib-2.0 | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_glibtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$GLIB_LIBS $LIBS" +dnl +dnl Now check if the installed GLIB is sufficiently new. (Also sanity +dnl checks the results of pkg-config to some extent) +dnl + rm -f conf.glibtest + AC_TRY_RUN([ +#include +#include +#include + +int +main (void) +{ + unsigned int major, minor, micro; + + fclose (fopen ("conf.glibtest", "w")); + + if (sscanf("$min_glib_version", "%u.%u.%u", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_glib_version"); + exit(1); + } + + if ((glib_major_version != $glib_config_major_version) || + (glib_minor_version != $glib_config_minor_version) || + (glib_micro_version != $glib_config_micro_version)) + { + printf("\n*** 'pkg-config --modversion glib-2.0' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", + $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, + glib_major_version, glib_minor_version, glib_micro_version); + printf ("*** was found! If pkg-config was correct, then it is best\n"); + printf ("*** to remove the old version of GLib. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); + printf("*** to point to the correct configuration files\n"); + } + else if ((glib_major_version != GLIB_MAJOR_VERSION) || + (glib_minor_version != GLIB_MINOR_VERSION) || + (glib_micro_version != GLIB_MICRO_VERSION)) + { + printf("*** GLIB header files (version %d.%d.%d) do not match\n", + GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); + printf("*** library (version %d.%d.%d)\n", + glib_major_version, glib_minor_version, glib_micro_version); + } + else + { + if ((glib_major_version > major) || + ((glib_major_version == major) && (glib_minor_version > minor)) || + ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GLIB (%u.%u.%u) was found.\n", + glib_major_version, glib_minor_version, glib_micro_version); + printf("*** You need a version of GLIB newer than %u.%u.%u. The latest version of\n", + major, minor, micro); + printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GLIB, but you can also set the PKG_CONFIG environment to point to the\n"); + printf("*** correct copy of pkg-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} +],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_glib" = x ; then + AC_MSG_RESULT(yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$PKG_CONFIG" = "no" ; then + echo "*** A new enough version of pkg-config was not found." + echo "*** See http://www.freedesktop.org/software/pkgconfig/" + else + if test -f conf.glibtest ; then + : + else + echo "*** Could not run GLIB test program, checking why..." + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$LIBS $GLIB_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GLIB or finding the wrong" + echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GLIB is incorrectly installed."]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GLIB_CFLAGS="" + GLIB_LIBS="" + GLIB_GENMARSHAL="" + GOBJECT_QUERY="" + GLIB_MKENUMS="" + GLIB_COMPILE_RESOURCES="" + ifelse([$3], , :, [$3]) + fi + rm -f conf.glibtest +]) + +# gpgme.m4 - autoconf macro to detect GPGME. +# Copyright (C) 2002, 2003, 2004, 2014, 2018 g10 Code GmbH +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Last-changed: 2018-11-12 + + +AC_DEFUN([_AM_PATH_GPGME_CONFIG], +[ AC_ARG_WITH(gpgme-prefix, + AC_HELP_STRING([--with-gpgme-prefix=PFX], + [prefix where GPGME is installed (optional)]), + gpgme_config_prefix="$withval", gpgme_config_prefix="") + if test x"${GPGME_CONFIG}" = x ; then + if test x"${gpgme_config_prefix}" != x ; then + GPGME_CONFIG="${gpgme_config_prefix}/bin/gpgme-config" + else + case "${SYSROOT}" in + /*) + if test -x "${SYSROOT}/bin/gpgme-config" ; then + GPGME_CONFIG="${SYSROOT}/bin/gpgme-config" + fi + ;; + '') + ;; + *) + AC_MSG_WARN([Ignoring \$SYSROOT as it is not an absolute path.]) + ;; + esac + fi + fi + + use_gpgrt_config="" + if test x"${GPGME_CONFIG}" = x -a x"$GPGRT_CONFIG" != x -a "$GPGRT_CONFIG" != "no"; then + if $GPGRT_CONFIG gpgme --exists; then + GPGME_CONFIG="$GPGRT_CONFIG gpgme" + AC_MSG_NOTICE([Use gpgrt-config as gpgme-config]) + use_gpgrt_config=yes + fi + fi + if test -z "$use_gpgrt_config"; then + AC_PATH_PROG(GPGME_CONFIG, gpgme-config, no) + fi + + if test "$GPGME_CONFIG" != "no" ; then + if test -z "$use_gpgrt_config"; then + gpgme_version=`$GPGME_CONFIG --version` + else + gpgme_version=`$GPGME_CONFIG --modversion` + fi + fi + gpgme_version_major=`echo $gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + gpgme_version_minor=`echo $gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + gpgme_version_micro=`echo $gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` +]) + + +AC_DEFUN([_AM_PATH_GPGME_CONFIG_HOST_CHECK], +[ + if test -z "$use_gpgrt_config"; then + gpgme_config_host=`$GPGME_CONFIG --host 2>/dev/null || echo none` + else + gpgme_config_host=`$GPGME_CONFIG --variable=host 2>/dev/null || echo none` + fi + if test x"$gpgme_config_host" != xnone ; then + if test x"$gpgme_config_host" != x"$host" ; then + AC_MSG_WARN([[ +*** +*** The config script "$GPGME_CONFIG" was +*** built for $gpgme_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-gpgme-prefix +*** to specify a matching config script or use \$SYSROOT. +***]]) + gpg_config_script_warn="$gpg_config_script_warn gpgme" + fi + fi +]) + + +dnl AM_PATH_GPGME([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgpgme and define GPGME_CFLAGS and GPGME_LIBS. +dnl +dnl If a prefix option is not used, the config script is first +dnl searched in $SYSROOT/bin and then along $PATH. If the used +dnl config script does not match the host specification the script +dnl is added to the gpg_config_script_warn variable. +dnl +AC_DEFUN([AM_PATH_GPGME], +[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl + tmp=ifelse([$1], ,1:0.4.2,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_gpgme_api=0 + min_gpgme_version="$tmp" + fi + + AC_MSG_CHECKING(for GPGME - version >= $min_gpgme_version) + ok=no + if test "$GPGME_CONFIG" != "no" ; then + req_major=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + if test "$gpgme_version_major" -gt "$req_major"; then + ok=yes + else + if test "$gpgme_version_major" -eq "$req_major"; then + if test "$gpgme_version_minor" -gt "$req_minor"; then + ok=yes + else + if test "$gpgme_version_minor" -eq "$req_minor"; then + if test "$gpgme_version_micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent GPGME, we should also check that the + # API is compatible. + if test "$req_gpgme_api" -gt 0 ; then + if test -z "$use_gpgrt_config"; then + tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0` + else + tmp=`$GPGME_CONFIG --variable=api_version 2>/dev/null || echo 0` + fi + if test "$tmp" -gt 0 ; then + if test "$req_gpgme_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + GPGME_CFLAGS=`$GPGME_CONFIG --cflags` + GPGME_LIBS=`$GPGME_CONFIG --libs` + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + _AM_PATH_GPGME_CONFIG_HOST_CHECK + else + GPGME_CFLAGS="" + GPGME_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPGME_CFLAGS) + AC_SUBST(GPGME_LIBS) +]) + +dnl AM_PATH_GPGME_PTHREAD([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgpgme and define GPGME_PTHREAD_CFLAGS +dnl and GPGME_PTHREAD_LIBS. +dnl +AC_DEFUN([AM_PATH_GPGME_PTHREAD], +[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl + tmp=ifelse([$1], ,1:0.4.2,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_gpgme_api=0 + min_gpgme_version="$tmp" + fi + + AC_MSG_CHECKING(for GPGME pthread - version >= $min_gpgme_version) + ok=no + if test "$GPGME_CONFIG" != "no" ; then + if `$GPGME_CONFIG --thread=pthread 2> /dev/null` ; then + req_major=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + if test "$gpgme_version_major" -gt "$req_major"; then + ok=yes + else + if test "$gpgme_version_major" -eq "$req_major"; then + if test "$gpgme_version_minor" -gt "$req_minor"; then + ok=yes + else + if test "$gpgme_version_minor" -eq "$req_minor"; then + if test "$gpgme_version_micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent GPGME, we should also check that the + # API is compatible. + if test "$req_gpgme_api" -gt 0 ; then + tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + if test "$req_gpgme_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + GPGME_PTHREAD_CFLAGS=`$GPGME_CONFIG --thread=pthread --cflags` + GPGME_PTHREAD_LIBS=`$GPGME_CONFIG --thread=pthread --libs` + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + _AM_PATH_GPGME_CONFIG_HOST_CHECK + else + GPGME_PTHREAD_CFLAGS="" + GPGME_PTHREAD_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPGME_PTHREAD_CFLAGS) + AC_SUBST(GPGME_PTHREAD_LIBS) +]) + + +dnl AM_PATH_GPGME_GLIB([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgpgme-glib and define GPGME_GLIB_CFLAGS and GPGME_GLIB_LIBS. +dnl +AC_DEFUN([AM_PATH_GPGME_GLIB], +[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl + tmp=ifelse([$1], ,1:0.4.2,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_gpgme_api=0 + min_gpgme_version="$tmp" + fi + + AC_MSG_CHECKING(for GPGME - version >= $min_gpgme_version) + ok=no + if test "$GPGME_CONFIG" != "no" ; then + req_major=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + if test "$gpgme_version_major" -gt "$req_major"; then + ok=yes + else + if test "$gpgme_version_major" -eq "$req_major"; then + if test "$gpgme_version_minor" -gt "$req_minor"; then + ok=yes + else + if test "$gpgme_version_minor" -eq "$req_minor"; then + if test "$gpgme_version_micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent GPGME, we should also check that the + # API is compatible. + if test "$req_gpgme_api" -gt 0 ; then + if test -z "$use_gpgrt_config"; then + tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0` + else + tmp=`$GPGME_CONFIG --variable=api_version 2>/dev/null || echo 0` + fi + if test "$tmp" -gt 0 ; then + if test "$req_gpgme_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + if test -z "$use_gpgrt_config"; then + GPGME_GLIB_CFLAGS=`$GPGME_CONFIG --glib --cflags` + GPGME_GLIB_LIBS=`$GPGME_CONFIG --glib --libs` + else + if $GPGRT_CONFIG gpgme-glib --exists; then + GPGME_CONFIG="$GPGRT_CONFIG gpgme-glib" + GPGME_GLIB_CFLAGS=`$GPGME_CONFIG --cflags` + GPGME_GLIB_LIBS=`$GPGME_CONFIG --libs` + else + ok = no + fi + fi + fi + if test $ok = yes; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + _AM_PATH_GPGME_CONFIG_HOST_CHECK + else + GPGME_GLIB_CFLAGS="" + GPGME_GLIB_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPGME_GLIB_CFLAGS) + AC_SUBST(GPGME_GLIB_LIBS) +]) + +dnl -*- mode: autoconf -*- +dnl Copyright 2009 Johan Dahlin +dnl +dnl This file is free software; the author(s) gives unlimited +dnl permission to copy and/or distribute it, with or without +dnl modifications, as long as this notice is preserved. +dnl + +# serial 1 + +dnl This is a copy of AS_AC_EXPAND +dnl +dnl (C) 2003, 2004, 2005 Thomas Vander Stichele +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. +m4_define([_GOBJECT_INTROSPECTION_AS_AC_EXPAND], +[ + EXP_VAR=[$1] + FROM_VAR=[$2] + + dnl first expand prefix and exec_prefix if necessary + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + dnl if no prefix given, then use /usr/local, the default prefix + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + dnl if no exec_prefix given, then use prefix + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + dnl loop until it doesn't change anymore + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + dnl clean up + full_var=$new_full_var + AC_SUBST([$1], "$full_var") + + dnl restore prefix and exec_prefix + prefix=$prefix_save + exec_prefix=$exec_prefix_save +]) + +m4_define([_GOBJECT_INTROSPECTION_CHECK_INTERNAL], +[ + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([LT_INIT],[$0])dnl setup libtool first + + dnl enable/disable introspection + m4_if([$2], [require], + [dnl + enable_introspection=yes + ],[dnl + AC_ARG_ENABLE(introspection, + AS_HELP_STRING([--enable-introspection[=@<:@no/auto/yes@:>@]], + [Enable introspection for this build]),, + [enable_introspection=auto]) + ])dnl + + AC_MSG_CHECKING([for gobject-introspection]) + + dnl presence/version checking + AS_CASE([$enable_introspection], + [no], [dnl + found_introspection="no (disabled, use --enable-introspection to enable)" + ],dnl + [yes],[dnl + PKG_CHECK_EXISTS([gobject-introspection-1.0],, + AC_MSG_ERROR([gobject-introspection-1.0 is not installed])) + PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], + found_introspection=yes, + AC_MSG_ERROR([You need to have gobject-introspection >= $1 installed to build AC_PACKAGE_NAME])) + ],dnl + [auto],[dnl + PKG_CHECK_EXISTS([gobject-introspection-1.0 >= $1], found_introspection=yes, found_introspection=no) + dnl Canonicalize enable_introspection + enable_introspection=$found_introspection + ],dnl + [dnl + AC_MSG_ERROR([invalid argument passed to --enable-introspection, should be one of @<:@no/auto/yes@:>@]) + ])dnl + + AC_MSG_RESULT([$found_introspection]) + + dnl expand datadir/libdir so we can pass them to pkg-config + dnl and get paths relative to our target directories + _GOBJECT_INTROSPECTION_AS_AC_EXPAND(_GI_EXP_DATADIR, "$datadir") + _GOBJECT_INTROSPECTION_AS_AC_EXPAND(_GI_EXP_LIBDIR, "$libdir") + + INTROSPECTION_SCANNER= + INTROSPECTION_COMPILER= + INTROSPECTION_GENERATE= + INTROSPECTION_GIRDIR= + INTROSPECTION_TYPELIBDIR= + if test "x$found_introspection" = "xyes"; then + INTROSPECTION_SCANNER=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` + INTROSPECTION_COMPILER=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` + INTROSPECTION_GENERATE=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` + INTROSPECTION_GIRDIR=`$PKG_CONFIG --define-variable=datadir="${_GI_EXP_DATADIR}" --variable=girdir gobject-introspection-1.0` + INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --define-variable=libdir="${_GI_EXP_LIBDIR}" --variable=typelibdir gobject-introspection-1.0)" + INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` + INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` + INTROSPECTION_MAKEFILE=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection + fi + AC_SUBST(INTROSPECTION_SCANNER) + AC_SUBST(INTROSPECTION_COMPILER) + AC_SUBST(INTROSPECTION_GENERATE) + AC_SUBST(INTROSPECTION_GIRDIR) + AC_SUBST(INTROSPECTION_TYPELIBDIR) + AC_SUBST(INTROSPECTION_CFLAGS) + AC_SUBST(INTROSPECTION_LIBS) + AC_SUBST(INTROSPECTION_MAKEFILE) + + AM_CONDITIONAL(HAVE_INTROSPECTION, test "x$found_introspection" = "xyes") +]) + + +dnl Usage: +dnl GOBJECT_INTROSPECTION_CHECK([minimum-g-i-version]) + +AC_DEFUN([GOBJECT_INTROSPECTION_CHECK], +[ + _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1]) +]) + +dnl Usage: +dnl GOBJECT_INTROSPECTION_REQUIRE([minimum-g-i-version]) + + +AC_DEFUN([GOBJECT_INTROSPECTION_REQUIRE], +[ + _GOBJECT_INTROSPECTION_CHECK_INTERNAL([$1], [require]) +]) + +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 11 (pkg-config-0.29.1) + +dnl Copyright © 2004 Scott James Remnant . +dnl Copyright © 2012-2015 Dan Nicholson +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.1]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have to call PKG_CHECK_EXISTS manually +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR + +dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------ +dnl +dnl Prepare a "--with-" configure option using the lowercase +dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and +dnl PKG_CHECK_MODULES in a single macro. +AC_DEFUN([PKG_WITH_MODULES], +[ +m4_pushdef([with_arg], m4_tolower([$1])) + +m4_pushdef([description], + [m4_default([$5], [build with ]with_arg[ support])]) + +m4_pushdef([def_arg], [m4_default([$6], [auto])]) +m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) +m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) + +m4_case(def_arg, + [yes],[m4_pushdef([with_without], [--without-]with_arg)], + [m4_pushdef([with_without],[--with-]with_arg)]) + +AC_ARG_WITH(with_arg, + AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, + [AS_TR_SH([with_]with_arg)=def_arg]) + +AS_CASE([$AS_TR_SH([with_]with_arg)], + [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], + [auto],[PKG_CHECK_MODULES([$1],[$2], + [m4_n([def_action_if_found]) $3], + [m4_n([def_action_if_not_found]) $4])]) + +m4_popdef([with_arg]) +m4_popdef([description]) +m4_popdef([def_arg]) + +])dnl PKG_WITH_MODULES + +dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ----------------------------------------------- +dnl +dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES +dnl check._[VARIABLE-PREFIX] is exported as make variable. +AC_DEFUN([PKG_HAVE_WITH_MODULES], +[ +PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) + +AM_CONDITIONAL([HAVE_][$1], + [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) +])dnl PKG_HAVE_WITH_MODULES + +dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +dnl [DESCRIPTION], [DEFAULT]) +dnl ------------------------------------------------------ +dnl +dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after +dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make +dnl and preprocessor variable. +AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], +[ +PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) + +AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], + [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) +])dnl PKG_HAVE_DEFINE_WITH_MODULES + +# Copyright (C) 2002-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.16' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.16.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.16.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_COND_IF -*- Autoconf -*- + +# Copyright (C) 2008-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_COND_IF +# _AM_COND_ELSE +# _AM_COND_ENDIF +# -------------- +# These macros are only used for tracing. +m4_define([_AM_COND_IF]) +m4_define([_AM_COND_ELSE]) +m4_define([_AM_COND_ENDIF]) + +# AM_COND_IF(COND, [IF-TRUE], [IF-FALSE]) +# --------------------------------------- +# If the shell condition COND is true, execute IF-TRUE, otherwise execute +# IF-FALSE. Allow automake to learn about conditional instantiating macros +# (the AC_CONFIG_FOOS). +AC_DEFUN([AM_COND_IF], +[m4_ifndef([_AM_COND_VALUE_$1], + [m4_fatal([$0: no such condition "$1"])])dnl +_AM_COND_IF([$1])dnl +if test -z "$$1_TRUE"; then : + m4_n([$2])[]dnl +m4_ifval([$3], +[_AM_COND_ELSE([$1])dnl +else + $3 +])dnl +_AM_COND_ENDIF([$1])dnl +fi[]dnl +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + AS_CASE([$CONFIG_FILES], + [*\'*], [eval set x "$CONFIG_FILES"], + [*], [set x $CONFIG_FILES]) + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`AS_DIRNAME(["$am_mf"])` + am_filepart=`AS_BASENAME(["$am_mf"])` + AM_RUN_LOG([cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles]) || am_rc=$? + done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. Try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi + AS_UNSET([am_dirpart]) + AS_UNSET([am_filepart]) + AS_UNSET([am_mf]) + AS_UNSET([am_rc]) + rm -f conftest-deps.mk +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking is enabled. +# This creates each '.Po' and '.Plo' makefile fragment that we'll need in +# order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless 'enable' is passed literally. +# For symmetry, 'disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], + am_maintainer_other[ make rules and dependencies not useful + (and sometimes confusing) to the casual installer])], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check whether make has an 'include' directive that can support all +# the idioms we need for our automatic dependency tracking code. +AC_DEFUN([AM_MAKE_INCLUDE], +[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) + AS_CASE([$?:`cat confinc.out 2>/dev/null`], + ['0:this is the am__doit target'], + [AS_CASE([$s], + [BSD], [am__include='.include' am__quote='"'], + [am__include='include' am__quote=''])]) + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +AC_MSG_RESULT([${_am_result}]) +AC_SUBST([am__include])]) +AC_SUBST([am__quote])]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2018 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([buildutil/attributes.m4]) +m4_include([buildutil/glibtests.m4]) +m4_include([buildutil/gtk-doc.m4]) +m4_include([buildutil/libglnx.m4]) +m4_include([buildutil/libtool.m4]) +m4_include([buildutil/ltoptions.m4]) +m4_include([buildutil/ltsugar.m4]) +m4_include([buildutil/ltversion.m4]) +m4_include([buildutil/lt~obsolete.m4]) diff --git a/apidoc/Makefile.am b/apidoc/Makefile.am new file mode 100644 index 0000000..98a84d5 --- /dev/null +++ b/apidoc/Makefile.am @@ -0,0 +1,128 @@ +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +abs_top_builddir = @abs_top_builddir@ + +include ../Makefile-libostree-defines.am + +NULL = + +# We require automake 1.6 at least. +AUTOMAKE_OPTIONS = 1.6 + +# The name of the module, e.g. 'glib'. +DOC_MODULE=ostree + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR=$(top_srcdir)/src/libostree + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS= --version + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS= --rebuild-types + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS=--sgml-mode --output-format=xml + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS= + +# MKHTML_OPTIONS=--path="$(builddir)/html $(srcdir)/html" + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS= + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB=$(addprefix $(top_srcdir)/,$(libostree_public_headers)) $(addprefix $(top_builddir)/,$(libostree_public_built_headers)) +CFILE_GLOB=$(top_srcdir)/src/libostree/*.c + +# Header files to ignore when scanning. +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES= \ + bupsplit.h \ + ostree-bootloader.h \ + ostree-bootloader-grub2.h \ + ostree-bootloader-syslinux.h \ + ostree-bootloader-uboot.h \ + ostree-cmdprivate.h \ + ostree-core-private.h \ + ostree-fetcher.h \ + ostree-gpg-verifier.h \ + ostree-gpg-verify-result-private.h \ + ostree-libarchive-input-stream.h \ + ostree-lzma-compressor.h \ + ostree-lzma-decompressor.h \ + ostree-metalink.h \ + ostree-repo-file-enumerator.h \ + ostree-repo-private.h \ + ostree-repo-pull-private.h \ + ostree-repo-static-delta-private.h \ + ostree-sysroot-private.h \ + ostree-tls-cert-interaction.h \ + $(NULL) + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES= + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files= \ + $(NULL) + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files= \ + version.xml \ + $(NULL) + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) +GTKDOC_LIBS= + +version.xml: + echo -n $(VERSION) > "$@" + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/gtk-doc.make + +EXTRA_DIST += \ + version.xml \ + ostree-sections.txt \ + ostree-experimental-sections.txt \ + $(NULL) + +-include $(top_srcdir)/git.mk diff --git a/apidoc/Makefile.in b/apidoc/Makefile.in new file mode 100644 index 0000000..db2d7da --- /dev/null +++ b/apidoc/Makefile.in @@ -0,0 +1,1005 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Shared variables between toplevel Makefile.am and doc/Makefile.am +# ...since gtk-doc forces use of recursive make =( +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# -*- mode: makefile -*- +# +# gtk-doc.make - make rules for gtk-doc +# Copyright (C) 2003 James Henstridge +# 2004-2007 Damon Chaplin +# 2007-2017 Stefan Sauer +# +# 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +#################################### +# Everything below here is generic # +#################################### +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = apidoc +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/buildutil/attributes.m4 \ + $(top_srcdir)/buildutil/glibtests.m4 \ + $(top_srcdir)/buildutil/gtk-doc.m4 \ + $(top_srcdir)/buildutil/libglnx.m4 \ + $(top_srcdir)/buildutil/libtool.m4 \ + $(top_srcdir)/buildutil/ltoptions.m4 \ + $(top_srcdir)/buildutil/ltsugar.m4 \ + $(top_srcdir)/buildutil/ltversion.m4 \ + $(top_srcdir)/buildutil/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/../Makefile-libostree-defines.am \ + $(srcdir)/Makefile.in $(top_srcdir)/gtk-doc.make +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASH_COMPLETIONSDIR = @BASH_COMPLETIONSDIR@ +BUILDOPT_FUSE_CFLAGS = @BUILDOPT_FUSE_CFLAGS@ +BUILDOPT_FUSE_LIBS = @BUILDOPT_FUSE_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GJS = @GJS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GPGME_CONFIG = @GPGME_CONFIG@ +GPGME_PTHREAD_CFLAGS = @GPGME_PTHREAD_CFLAGS@ +GPGME_PTHREAD_LIBS = @GPGME_PTHREAD_LIBS@ +GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@ +GREP = @GREP@ +GRUB2_MKCONFIG = @GRUB2_MKCONFIG@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTROSPECTION_CFLAGS = @INTROSPECTION_CFLAGS@ +INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@ +INTROSPECTION_GENERATE = @INTROSPECTION_GENERATE@ +INTROSPECTION_GIRDIR = @INTROSPECTION_GIRDIR@ +INTROSPECTION_LIBS = @INTROSPECTION_LIBS@ +INTROSPECTION_MAKEFILE = @INTROSPECTION_MAKEFILE@ +INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@ +INTROSPECTION_TYPELIBDIR = @INTROSPECTION_TYPELIBDIR@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ +LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OSTREE_FEATURES = @OSTREE_FEATURES@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +OT_DEP_AVAHI_CFLAGS = @OT_DEP_AVAHI_CFLAGS@ +OT_DEP_AVAHI_LIBS = @OT_DEP_AVAHI_LIBS@ +OT_DEP_CRYPTO_CFLAGS = @OT_DEP_CRYPTO_CFLAGS@ +OT_DEP_CRYPTO_LIBS = @OT_DEP_CRYPTO_LIBS@ +OT_DEP_CURL_CFLAGS = @OT_DEP_CURL_CFLAGS@ +OT_DEP_CURL_LIBS = @OT_DEP_CURL_LIBS@ +OT_DEP_E2P_CFLAGS = @OT_DEP_E2P_CFLAGS@ +OT_DEP_E2P_LIBS = @OT_DEP_E2P_LIBS@ +OT_DEP_GIO_UNIX_CFLAGS = @OT_DEP_GIO_UNIX_CFLAGS@ +OT_DEP_GIO_UNIX_LIBS = @OT_DEP_GIO_UNIX_LIBS@ +OT_DEP_GPGME_CFLAGS = @OT_DEP_GPGME_CFLAGS@ +OT_DEP_GPGME_LIBS = @OT_DEP_GPGME_LIBS@ +OT_DEP_GPG_ERROR_CFLAGS = @OT_DEP_GPG_ERROR_CFLAGS@ +OT_DEP_GPG_ERROR_LIBS = @OT_DEP_GPG_ERROR_LIBS@ +OT_DEP_LIBARCHIVE_CFLAGS = @OT_DEP_LIBARCHIVE_CFLAGS@ +OT_DEP_LIBARCHIVE_LIBS = @OT_DEP_LIBARCHIVE_LIBS@ +OT_DEP_LIBMOUNT_CFLAGS = @OT_DEP_LIBMOUNT_CFLAGS@ +OT_DEP_LIBMOUNT_LIBS = @OT_DEP_LIBMOUNT_LIBS@ +OT_DEP_LIBSODIUM_CFLAGS = @OT_DEP_LIBSODIUM_CFLAGS@ +OT_DEP_LIBSODIUM_LIBS = @OT_DEP_LIBSODIUM_LIBS@ +OT_DEP_LZMA_CFLAGS = @OT_DEP_LZMA_CFLAGS@ +OT_DEP_LZMA_LIBS = @OT_DEP_LZMA_LIBS@ +OT_DEP_SELINUX_CFLAGS = @OT_DEP_SELINUX_CFLAGS@ +OT_DEP_SELINUX_LIBS = @OT_DEP_SELINUX_LIBS@ +OT_DEP_SOUP_CFLAGS = @OT_DEP_SOUP_CFLAGS@ +OT_DEP_SOUP_LIBS = @OT_DEP_SOUP_LIBS@ +OT_DEP_ZLIB_CFLAGS = @OT_DEP_ZLIB_CFLAGS@ +OT_DEP_ZLIB_LIBS = @OT_DEP_ZLIB_LIBS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE_VERSION = @RELEASE_VERSION@ +RUST_TARGET_SUBDIR = @RUST_TARGET_SUBDIR@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STATIC_COMPILER = @STATIC_COMPILER@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XSLTPROC = @XSLTPROC@ +YACC = @YACC@ +YEAR_VERSION = @YEAR_VERSION@ +YFLAGS = @YFLAGS@ +_GI_EXP_DATADIR = @_GI_EXP_DATADIR@ +_GI_EXP_LIBDIR = @_GI_EXP_LIBDIR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cargo = @cargo@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +installed_test_metadir = @installed_test_metadir@ +installed_testdir = @installed_testdir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rustc = @rustc@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemdsystemgeneratordir = @systemdsystemgeneratordir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +libostree_public_headers = \ + src/libostree/ostree.h \ + src/libostree/ostree-async-progress.h \ + src/libostree/ostree-autocleanups.h \ + src/libostree/ostree-core.h \ + src/libostree/ostree-dummy-enumtypes.h \ + src/libostree/ostree-mutable-tree.h \ + src/libostree/ostree-repo.h \ + src/libostree/ostree-types.h \ + src/libostree/ostree-repo-file.h \ + src/libostree/ostree-diff.h \ + src/libostree/ostree-gpg-verify-result.h \ + src/libostree/ostree-sepolicy.h \ + src/libostree/ostree-sysroot.h \ + src/libostree/ostree-sysroot-upgrader.h \ + src/libostree/ostree-deployment.h \ + src/libostree/ostree-bootconfig-parser.h \ + src/libostree/ostree-repo-deprecated.h \ + src/libostree/ostree-ref.h \ + src/libostree/ostree-remote.h \ + src/libostree/ostree-repo-finder.h \ + src/libostree/ostree-repo-finder-avahi.h \ + src/libostree/ostree-repo-finder-config.h \ + src/libostree/ostree-repo-finder-mount.h \ + src/libostree/ostree-repo-finder-override.h \ + src/libostree/ostree-kernel-args.h \ + src/libostree/ostree-sign.h \ + src/libostree/ostree-sign-ed25519.h \ + $(NULL) + + +# This one is generated via configure.ac, and the gtk-doc +# code hence needs to look in the builddir. +libostree_public_built_headers = src/libostree/ostree-version.h +NULL = + +# We require automake 1.6 at least. +AUTOMAKE_OPTIONS = 1.6 + +# The name of the module, e.g. 'glib'. +DOC_MODULE = ostree + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR = $(top_srcdir)/src/libostree + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS = --version + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS = --rebuild-types + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS = --sgml-mode --output-format=xml + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS = + +# MKHTML_OPTIONS=--path="$(builddir)/html $(srcdir)/html" + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS = + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB = $(addprefix $(top_srcdir)/,$(libostree_public_headers)) $(addprefix $(top_builddir)/,$(libostree_public_built_headers)) +CFILE_GLOB = $(top_srcdir)/src/libostree/*.c + +# Header files to ignore when scanning. +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES = \ + bupsplit.h \ + ostree-bootloader.h \ + ostree-bootloader-grub2.h \ + ostree-bootloader-syslinux.h \ + ostree-bootloader-uboot.h \ + ostree-cmdprivate.h \ + ostree-core-private.h \ + ostree-fetcher.h \ + ostree-gpg-verifier.h \ + ostree-gpg-verify-result-private.h \ + ostree-libarchive-input-stream.h \ + ostree-lzma-compressor.h \ + ostree-lzma-decompressor.h \ + ostree-metalink.h \ + ostree-repo-file-enumerator.h \ + ostree-repo-private.h \ + ostree-repo-pull-private.h \ + ostree-repo-static-delta-private.h \ + ostree-sysroot-private.h \ + ostree-tls-cert-interaction.h \ + $(NULL) + + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES = + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files = \ + $(NULL) + + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files = \ + version.xml \ + $(NULL) + + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) +GTKDOC_LIBS = +@GTK_DOC_USE_LIBTOOL_FALSE@GTKDOC_CC = $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +@GTK_DOC_USE_LIBTOOL_TRUE@GTKDOC_CC = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +@GTK_DOC_USE_LIBTOOL_FALSE@GTKDOC_LD = $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) +@GTK_DOC_USE_LIBTOOL_TRUE@GTKDOC_LD = $(LIBTOOL) --tag=CC --mode=link $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) +@GTK_DOC_USE_LIBTOOL_FALSE@GTKDOC_RUN = +@GTK_DOC_USE_LIBTOOL_TRUE@GTKDOC_RUN = $(LIBTOOL) --mode=execute + +# We set GPATH here; this gives us semantics for GNU make +# which are more like other make's VPATH, when it comes to +# whether a source that is a target of one rule is then +# searched for in VPATH/GPATH. +# +GPATH = $(srcdir) +TARGET_DIR = $(HTML_DIR)/$(DOC_MODULE) +SETUP_FILES = \ + $(content_files) \ + $(expand_content_files) \ + $(DOC_MAIN_SGML_FILE) \ + $(DOC_MODULE)-sections.txt \ + $(DOC_MODULE)-overrides.txt + + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +EXTRA_DIST = $(HTML_IMAGES) $(SETUP_FILES) version.xml \ + ostree-sections.txt ostree-experimental-sections.txt $(NULL) +DOC_STAMPS = setup-build.stamp scan-build.stamp sgml-build.stamp \ + html-build.stamp pdf-build.stamp \ + sgml.stamp html.stamp pdf.stamp + +SCANOBJ_FILES = \ + $(DOC_MODULE).args \ + $(DOC_MODULE).hierarchy \ + $(DOC_MODULE).interfaces \ + $(DOC_MODULE).prerequisites \ + $(DOC_MODULE).signals + +REPORT_FILES = \ + $(DOC_MODULE)-undocumented.txt \ + $(DOC_MODULE)-undeclared.txt \ + $(DOC_MODULE)-unused.txt + +CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS) gtkdoc-check.test +@GTK_DOC_BUILD_HTML_FALSE@HTML_BUILD_STAMP = +@GTK_DOC_BUILD_HTML_TRUE@HTML_BUILD_STAMP = html-build.stamp +@GTK_DOC_BUILD_PDF_FALSE@PDF_BUILD_STAMP = +@GTK_DOC_BUILD_PDF_TRUE@PDF_BUILD_STAMP = pdf-build.stamp + +#### setup #### +GTK_DOC_V_SETUP = $(GTK_DOC_V_SETUP_@AM_V@) +GTK_DOC_V_SETUP_ = $(GTK_DOC_V_SETUP_@AM_DEFAULT_V@) +GTK_DOC_V_SETUP_0 = @echo " DOC Preparing build"; + +#### scan #### +GTK_DOC_V_SCAN = $(GTK_DOC_V_SCAN_@AM_V@) +GTK_DOC_V_SCAN_ = $(GTK_DOC_V_SCAN_@AM_DEFAULT_V@) +GTK_DOC_V_SCAN_0 = @echo " DOC Scanning header files"; +GTK_DOC_V_INTROSPECT = $(GTK_DOC_V_INTROSPECT_@AM_V@) +GTK_DOC_V_INTROSPECT_ = $(GTK_DOC_V_INTROSPECT_@AM_DEFAULT_V@) +GTK_DOC_V_INTROSPECT_0 = @echo " DOC Introspecting gobjects"; + +#### xml #### +GTK_DOC_V_XML = $(GTK_DOC_V_XML_@AM_V@) +GTK_DOC_V_XML_ = $(GTK_DOC_V_XML_@AM_DEFAULT_V@) +GTK_DOC_V_XML_0 = @echo " DOC Building XML"; + +#### html #### +GTK_DOC_V_HTML = $(GTK_DOC_V_HTML_@AM_V@) +GTK_DOC_V_HTML_ = $(GTK_DOC_V_HTML_@AM_DEFAULT_V@) +GTK_DOC_V_HTML_0 = @echo " DOC Building HTML"; +GTK_DOC_V_XREF = $(GTK_DOC_V_XREF_@AM_V@) +GTK_DOC_V_XREF_ = $(GTK_DOC_V_XREF_@AM_DEFAULT_V@) +GTK_DOC_V_XREF_0 = @echo " DOC Fixing cross-references"; + +#### pdf #### +GTK_DOC_V_PDF = $(GTK_DOC_V_PDF_@AM_V@) +GTK_DOC_V_PDF_ = $(GTK_DOC_V_PDF_@AM_DEFAULT_V@) +GTK_DOC_V_PDF_0 = @echo " DOC Building PDF"; +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../Makefile-libostree-defines.am $(top_srcdir)/gtk-doc.make $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign apidoc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign apidoc/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; +$(srcdir)/../Makefile-libostree-defines.am $(top_srcdir)/gtk-doc.make $(am__empty): + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook +check-am: all-am +check: check-am +@ENABLE_GTK_DOC_FALSE@all-local: +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-local + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-data-local + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic \ + maintainer-clean-local + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-local + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool clean-local cscopelist-am ctags-am dist-hook \ + distclean distclean-generic distclean-libtool distclean-local \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-data-local \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + maintainer-clean-local mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ + uninstall-am uninstall-local + +.PRECIOUS: Makefile + + +version.xml: + echo -n $(VERSION) > "$@" + +gtkdoc-check.test: Makefile + $(AM_V_GEN)echo "#!/bin/sh -e" > $@; \ + echo "$(GTKDOC_CHECK_PATH) || exit 1" >> $@; \ + chmod +x $@ + +all-gtk-doc: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP) +.PHONY: all-gtk-doc + +@ENABLE_GTK_DOC_TRUE@all-local: all-gtk-doc + +docs: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP) + +$(REPORT_FILES): sgml-build.stamp + +setup-build.stamp: + -$(GTK_DOC_V_SETUP)if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ + files=`echo $(SETUP_FILES) $(DOC_MODULE).types`; \ + if test "x$$files" != "x" ; then \ + for file in $$files ; do \ + destdir=`dirname $(abs_builddir)/$$file`; \ + test -d "$$destdir" || mkdir -p "$$destdir"; \ + test -f $(abs_srcdir)/$$file && \ + cp -pf $(abs_srcdir)/$$file $(abs_builddir)/$$file || true; \ + done; \ + fi; \ + fi + $(AM_V_at)touch setup-build.stamp + +scan-build.stamp: setup-build.stamp $(HFILE_GLOB) $(CFILE_GLOB) + $(GTK_DOC_V_SCAN)_source_dir='' ; \ + for i in $(DOC_SOURCE_DIR) ; do \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ + done ; \ + gtkdoc-scan --module=$(DOC_MODULE) --ignore-headers="$(IGNORE_HFILES)" $${_source_dir} $(SCAN_OPTIONS) $(EXTRA_HFILES) + $(GTK_DOC_V_INTROSPECT)if grep -l '^..*$$' $(DOC_MODULE).types > /dev/null 2>&1 ; then \ + scanobj_options=""; \ + gtkdoc-scangobj 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + scanobj_options="--verbose"; \ + fi; \ + fi; \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" \ + gtkdoc-scangobj $(SCANGOBJ_OPTIONS) $$scanobj_options --module=$(DOC_MODULE); \ + else \ + for i in $(SCANOBJ_FILES) ; do \ + test -f $$i || touch $$i ; \ + done \ + fi + $(AM_V_at)touch scan-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp + @true + +sgml-build.stamp: setup-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(HFILE_GLOB) $(CFILE_GLOB) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt $(expand_content_files) xml/gtkdocentities.ent + $(GTK_DOC_V_XML)_source_dir='' ; \ + for i in $(DOC_SOURCE_DIR) ; do \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ + done ; \ + gtkdoc-mkdb --module=$(DOC_MODULE) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $${_source_dir} $(MKDB_OPTIONS) + $(AM_V_at)touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +$(DOC_MAIN_SGML_FILE): sgml-build.stamp + @true + +xml/gtkdocentities.ent: Makefile + $(GTK_DOC_V_XML)$(MKDIR_P) $(@D) && ( \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + ) > $@ + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files) + $(GTK_DOC_V_HTML)rm -rf html && mkdir html && \ + mkhtml_options=""; \ + gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + mkhtml_options="$$mkhtml_options --verbose"; \ + fi; \ + fi; \ + gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \ + if test "$$?" = "0"; then \ + mkhtml_options="$$mkhtml_options --path=\"$(abs_srcdir)\""; \ + fi; \ + cd html && gtkdoc-mkhtml $$mkhtml_options $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) + -@test "x$(HTML_IMAGES)" = "x" || \ + for file in $(HTML_IMAGES) ; do \ + test -f $(abs_srcdir)/$$file && cp $(abs_srcdir)/$$file $(abs_builddir)/html; \ + test -f $(abs_builddir)/$$file && cp $(abs_builddir)/$$file $(abs_builddir)/html; \ + test -f $$file && cp $$file $(abs_builddir)/html; \ + done; + $(GTK_DOC_V_XREF)gtkdoc-fixxref --module=$(DOC_MODULE) --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + $(AM_V_at)touch html-build.stamp + +pdf-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files) + $(GTK_DOC_V_PDF)rm -f $(DOC_MODULE).pdf && \ + mkpdf_options=""; \ + gtkdoc-mkpdf 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + mkpdf_options="$$mkpdf_options --verbose"; \ + fi; \ + fi; \ + if test "x$(HTML_IMAGES)" != "x"; then \ + for img in $(HTML_IMAGES); do \ + part=`dirname $$img`; \ + echo $$mkpdf_options | grep >/dev/null "\-\-imgdir=$$part "; \ + if test $$? != 0; then \ + mkpdf_options="$$mkpdf_options --imgdir=$$part"; \ + fi; \ + done; \ + fi; \ + gtkdoc-mkpdf --path="$(abs_srcdir)" $$mkpdf_options $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) $(MKPDF_OPTIONS) + $(AM_V_at)touch pdf-build.stamp + +############## + +clean-local: + @rm -f *~ *.bak + @rm -rf .libs + @if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-types" ; then \ + rm -f $(DOC_MODULE).types; \ + fi + @if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-sections" ; then \ + rm -f $(DOC_MODULE)-sections.txt; \ + fi + +distclean-local: + @rm -rf xml html $(REPORT_FILES) $(DOC_MODULE).pdf \ + $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt + @if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ + rm -f $(SETUP_FILES) $(DOC_MODULE).types; \ + fi + +maintainer-clean-local: + @rm -rf xml html + +install-data-local: + @installfiles=`echo $(builddir)/html/*`; \ + if test "$$installfiles" = '$(builddir)/html/*'; \ + then echo 1>&2 'Nothing to install' ; \ + else \ + if test -n "$(DOC_MODULE_VERSION)"; then \ + installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ + else \ + installdir="$(DESTDIR)$(TARGET_DIR)"; \ + fi; \ + $(mkinstalldirs) $${installdir} ; \ + for i in $$installfiles; do \ + echo ' $(INSTALL_DATA) '$$i ; \ + $(INSTALL_DATA) $$i $${installdir}; \ + done; \ + if test -n "$(DOC_MODULE_VERSION)"; then \ + mv -f $${installdir}/$(DOC_MODULE).devhelp2 \ + $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp2; \ + fi; \ + $(GTKDOC_REBASE) --relative --dest-dir=$(DESTDIR) --html-dir=$${installdir}; \ + fi + +uninstall-local: + @if test -n "$(DOC_MODULE_VERSION)"; then \ + installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ + else \ + installdir="$(DESTDIR)$(TARGET_DIR)"; \ + fi; \ + rm -rf $${installdir} + +# +# Require gtk-doc when making dist +# +@HAVE_GTK_DOC_TRUE@dist-check-gtkdoc: docs +@HAVE_GTK_DOC_FALSE@dist-check-gtkdoc: +@HAVE_GTK_DOC_FALSE@ @echo "*** gtk-doc is needed to run 'make dist'. ***" +@HAVE_GTK_DOC_FALSE@ @echo "*** gtk-doc was not found when 'configure' ran. ***" +@HAVE_GTK_DOC_FALSE@ @echo "*** please install gtk-doc and rerun 'configure'. ***" +@HAVE_GTK_DOC_FALSE@ @false + +dist-hook: dist-check-gtkdoc all-gtk-doc dist-hook-local + @mkdir $(distdir)/html + @cp ./html/* $(distdir)/html + @-cp ./$(DOC_MODULE).pdf $(distdir)/ + @-cp ./$(DOC_MODULE).types $(distdir)/ + @-cp ./$(DOC_MODULE)-sections.txt $(distdir)/ + @cd $(distdir) && rm -f $(DISTCLEANFILES) + @$(GTKDOC_REBASE) --online --relative --html-dir=$(distdir)/html + +.PHONY : dist-hook-local docs + +-include $(top_srcdir)/git.mk + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/apidoc/html/home.png b/apidoc/html/home.png new file mode 100644 index 0000000..9346b33 Binary files /dev/null and b/apidoc/html/home.png differ diff --git a/apidoc/html/index.html b/apidoc/html/index.html new file mode 100644 index 0000000..cbd1e15 --- /dev/null +++ b/apidoc/html/index.html @@ -0,0 +1,76 @@ + + + + +OSTree API references: OSTree API references + + + + + + + +
+
+
+
+

for OSTree 2020.4

+
+
+
+
+
API Reference
+
+
+Core repository-independent functions — Create, validate, and convert core data types +
+
+OstreeRepo: Content-addressed object store — A git-like storage system for operating system binaries +
+
+In-memory modifiable filesystem tree — Modifiable filesystem tree +
+
+Root partition mount point — Manage physical root filesystem +
+
+Progress notification system for asynchronous operations — Values representing progress +
+
+SELinux policy management — Read SELinux policy and manage filesystem labels +
+
+Simple upgrade class — Upgrade OSTree systems +
+
+GPG signature verification results — Inspect detached GPG signatures +
+
+Signature management — Sign and verify commits +
+
+ostree-bootconfig-parser +
+
+ostree-chain-input-stream +
+
+ostree-checksum-input-stream +
+
+ostree-deployment +
+
+ostree-diff +
+
+ostree-repo-file +
+
API Index
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/left-insensitive.png b/apidoc/html/left-insensitive.png new file mode 100644 index 0000000..3269393 Binary files /dev/null and b/apidoc/html/left-insensitive.png differ diff --git a/apidoc/html/left.png b/apidoc/html/left.png new file mode 100644 index 0000000..2abde03 Binary files /dev/null and b/apidoc/html/left.png differ diff --git a/apidoc/html/ostree-Core-repository-independent-functions.html b/apidoc/html/ostree-Core-repository-independent-functions.html new file mode 100644 index 0000000..f56228a --- /dev/null +++ b/apidoc/html/ostree-Core-repository-independent-functions.html @@ -0,0 +1,2875 @@ + + + + +Core repository-independent functions: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

Core repository-independent functions

+

Core repository-independent functions — Create, validate, and convert core data types

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#define +OSTREE_OBJECT_TYPE_IS_META() +
const GVariantType * + +ostree_metadata_variant_type () +
+gboolean + +ostree_validate_checksum_string () +
+guchar * + +ostree_checksum_to_bytes () +
+GVariant * + +ostree_checksum_to_bytes_v () +
+char * + +ostree_checksum_from_bytes () +
+char * + +ostree_checksum_from_bytes_v () +
+void + +ostree_checksum_inplace_from_bytes () +
+void + +ostree_checksum_inplace_to_bytes () +
const guchar * + +ostree_checksum_bytes_peek () +
const guchar * + +ostree_checksum_bytes_peek_validate () +
+char * + +ostree_checksum_b64_from_bytes () +
+guchar * + +ostree_checksum_b64_to_bytes () +
+void + +ostree_checksum_b64_inplace_from_bytes () +
+void + +ostree_checksum_b64_inplace_to_bytes () +
+int + +ostree_cmp_checksum_bytes () +
+gboolean + +ostree_validate_rev () +
+gboolean + +ostree_validate_remote_name () +
+gboolean + +ostree_parse_refspec () +
const char * + +ostree_object_type_to_string () +
+OstreeObjectType + +ostree_object_type_from_string () +
+guint + +ostree_hash_object_name () +
+GVariant * + +ostree_object_name_serialize () +
+void + +ostree_object_name_deserialize () +
+char * + +ostree_object_to_string () +
+void + +ostree_object_from_string () +
+gboolean + +ostree_content_stream_parse () +
+gboolean + +ostree_content_file_parse () +
+gboolean + +ostree_content_file_parse_at () +
+gboolean + +ostree_raw_file_to_archive_z2_stream () +
+gboolean + +ostree_raw_file_to_archive_z2_stream_with_options () +
+gboolean + +ostree_raw_file_to_content_stream () +
+gboolean + +ostree_break_hardlink () +
+gboolean + +ostree_checksum_file_from_input () +
+gboolean + +ostree_checksum_file () +
+gboolean + +ostree_checksum_file_at () +
+void + +ostree_checksum_file_async () +
+gboolean + +ostree_checksum_file_async_finish () +
+GVariant * + +ostree_create_directory_metadata () +
+gboolean + +ostree_validate_structureof_objtype () +
+gboolean + +ostree_validate_structureof_csum_v () +
+gboolean + +ostree_validate_structureof_checksum_string () +
+gboolean + +ostree_validate_structureof_file_mode () +
+gboolean + +ostree_validate_structureof_commit () +
+gboolean + +ostree_validate_structureof_dirtree () +
+gboolean + +ostree_validate_structureof_dirmeta () +
+gchar * + +ostree_commit_get_parent () +
+guint64 + +ostree_commit_get_timestamp () +
+gchar * + +ostree_commit_get_content_checksum () +
+gboolean + +ostree_commit_get_object_sizes () +
+OstreeCommitSizesEntry * + +ostree_commit_sizes_entry_new () +
+OstreeCommitSizesEntry * + +ostree_commit_sizes_entry_copy () +
+void + +ostree_commit_sizes_entry_free () +
+gboolean + +ostree_check_version () +
+
+ +
+

Description

+

These functions implement repository-independent algorithms for +operating on the core OSTree data formats, such as converting +GFileInfo into a GVariant.

+

There are 4 types of objects; file, dirmeta, tree, and commit. The +last 3 are metadata, and the file object is the only content object +type.

+

All metadata objects are stored as GVariant (big endian). The +rationale for this is the same as that of the ext{2,3,4} family of +filesystems; most developers will be using LE, and so it's better +to continually test the BE->LE swap.

+

The file object is a custom format in order to support streaming.

+
+
+

Functions

+
+

OSTREE_OBJECT_TYPE_IS_META()

+
#define OSTREE_OBJECT_TYPE_IS_META(t) (t >= 2 && t <= 6)
+
+
+

Parameters

+
+++++ + + + + + +

t

An OstreeObjectType

 
+
+
+

Returns

+

TRUE if object type is metadata

+
+
+
+
+

ostree_metadata_variant_type ()

+
const GVariantType *
+ostree_metadata_variant_type (OstreeObjectType objtype);
+
+
+
+

ostree_validate_checksum_string ()

+
gboolean
+ostree_validate_checksum_string (const char *sha256,
+                                 GError **error);
+

Use this function to see if input strings are checksums.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

sha256

SHA256 hex string

 

error

Error

 
+
+
+

Returns

+

TRUE if sha256 +is a valid checksum string, FALSE otherwise

+
+
+
+
+

ostree_checksum_to_bytes ()

+
guchar *
+ostree_checksum_to_bytes (const char *checksum);
+
+

Parameters

+
+++++ + + + + + +

checksum

An ASCII checksum

 
+
+
+

Returns

+

Binary checksum from checksum +of length 32; free with g_free().

+

[transfer full][array fixed-size=32]

+
+
+
+
+

ostree_checksum_to_bytes_v ()

+
GVariant *
+ostree_checksum_to_bytes_v (const char *checksum);
+
+

Parameters

+
+++++ + + + + + +

checksum

An ASCII checksum

 
+
+
+

Returns

+

New GVariant of type ay with length 32.

+

[transfer full]

+
+
+
+
+

ostree_checksum_from_bytes ()

+
char *
+ostree_checksum_from_bytes (const guchar *csum);
+
+

Parameters

+
+++++ + + + + + +

csum

An binary checksum of length 32.

[array fixed-size=32]
+
+
+

Returns

+

String form of csum +.

+

[transfer full]

+
+
+
+
+

ostree_checksum_from_bytes_v ()

+
char *
+ostree_checksum_from_bytes_v (GVariant *csum_v);
+
+

Parameters

+
+++++ + + + + + +

csum_v

GVariant of type ay

 
+
+
+

Returns

+

String form of csum_bytes +.

+

[transfer full]

+
+
+
+
+

ostree_checksum_inplace_from_bytes ()

+
void
+ostree_checksum_inplace_from_bytes (const guchar *csum,
+                                    char *buf);
+

Overwrite the contents of buf + with stringified version of csum +.

+

[skip]

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

csum

An binary checksum of length 32.

[array fixed-size=32]

buf

Output location, must be at least OSTREE_SHA256_STRING_LEN+1 bytes in length

 
+
+
+
+
+

ostree_checksum_inplace_to_bytes ()

+
void
+ostree_checksum_inplace_to_bytes (const char *checksum,
+                                  guchar *buf);
+

Convert checksum + from a string to binary in-place, without +allocating memory. Use this function in hot code paths.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

checksum

a SHA256 string

 

buf

Output buffer with at least 32 bytes of space

 
+
+
+
+
+

ostree_checksum_bytes_peek ()

+
const guchar *
+ostree_checksum_bytes_peek (GVariant *bytes);
+
+

Parameters

+
+++++ + + + + + +

bytes

GVariant of type ay

 
+
+
+

Returns

+

Binary checksum data in bytes +; do not free. If bytes +does not have the correct length, return NULL.

+

[transfer none][array fixed-size=32][element-type guint8]

+
+
+
+
+

ostree_checksum_bytes_peek_validate ()

+
const guchar *
+ostree_checksum_bytes_peek_validate (GVariant *bytes,
+                                     GError **error);
+

Like ostree_checksum_bytes_peek(), but also throws error +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

bytes

GVariant of type ay

 

error

Errror

 
+
+
+

Returns

+

Binary checksum data.

+

[transfer none][array fixed-size=32][element-type guint8]

+
+
+
+
+

ostree_checksum_b64_from_bytes ()

+
char *
+ostree_checksum_b64_from_bytes (const guchar *csum);
+
+

Parameters

+
+++++ + + + + + +

csum

An binary checksum of length 32.

[array fixed-size=32]
+
+
+

Returns

+

Modified base64 encoding of csum +

+

The "modified" term refers to the fact that instead of '/', the '_' +character is used.

+

[transfer full]

+
+

Since: 2016.8

+
+
+
+

ostree_checksum_b64_to_bytes ()

+
guchar *
+ostree_checksum_b64_to_bytes (const char *checksum);
+
+

Parameters

+
+++++ + + + + + +

checksum

An ASCII checksum

 
+
+
+

Returns

+

Binary version of checksum +.

+

[transfer full][array fixed-size=32]

+
+

Since: 2016.8

+
+
+
+

ostree_checksum_b64_inplace_from_bytes ()

+
void
+ostree_checksum_b64_inplace_from_bytes
+                               (const guchar *csum,
+                                char *buf);
+

Overwrite the contents of buf + with modified base64 encoding of csum +. +The "modified" term refers to the fact that instead of '/', the '_' +character is used.

+

[skip]

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

csum

An binary checksum of length 32.

[array fixed-size=32]

buf

Output location, must be at least 44 bytes in length

 
+
+
+
+
+

ostree_checksum_b64_inplace_to_bytes ()

+
void
+ostree_checksum_b64_inplace_to_bytes (const char *checksum,
+                                      guint8 *buf);
+

Overwrite the contents of buf + with stringified version of csum +.

+

[skip]

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

checksum

An binary checksum of length 32.

[array fixed-size=32]

buf

Output location, must be at least 45 bytes in length

 
+
+
+
+
+

ostree_cmp_checksum_bytes ()

+
int
+ostree_cmp_checksum_bytes (const guchar *a,
+                           const guchar *b);
+

Compare two binary checksums, using memcmp().

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

a

A binary checksum

 

b

A binary checksum

 
+
+
+
+
+

ostree_validate_rev ()

+
gboolean
+ostree_validate_rev (const char *rev,
+                     GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

rev

A revision string

 

error

Error

 
+
+
+

Returns

+

TRUE if rev +is a valid ref string

+
+
+
+
+

ostree_validate_remote_name ()

+
gboolean
+ostree_validate_remote_name (const char *remote_name,
+                             GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

remote_name

A remote name

 

error

Error

 
+
+
+

Returns

+

TRUE if remote_name +is a valid remote name

+
+

Since: 2017.8

+
+
+
+

ostree_parse_refspec ()

+
gboolean
+ostree_parse_refspec (const char *refspec,
+                      char **out_remote,
+                      char **out_ref,
+                      GError **error);
+

Split a refspec like gnome-ostree:gnome-ostree/buildmaster or just +gnome-ostree/buildmaster into two parts. In the first case, out_remote + +will be set to gnome-ostree, and out_ref + to gnome-ostree/buildmaster. +In the second case (a local ref), out_remote + will be NULL, and out_ref + +will be gnome-ostree/buildmaster. In both cases, TRUE will be returned.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

refspec

A "refspec" string

 

out_remote

Return location for the remote name, +or NULL if the refspec refs to a local ref.

[out][nullable][optional]

out_ref

Return location for the ref name.

[out][not nullable][optional]

error

Error

 
+
+
+

Returns

+

TRUE on successful parsing, FALSE otherwise

+
+
+
+
+

ostree_object_type_to_string ()

+
const char *
+ostree_object_type_to_string (OstreeObjectType objtype);
+

Serialize objtype + to a string; this is used for file extensions.

+
+

Parameters

+
+++++ + + + + + +

objtype

an OstreeObjectType

 
+
+
+
+
+

ostree_object_type_from_string ()

+
OstreeObjectType
+ostree_object_type_from_string (const char *str);
+

The reverse of ostree_object_type_to_string().

+
+

Parameters

+
+++++ + + + + + +

str

A stringified version of OstreeObjectType

 
+
+
+
+
+

ostree_hash_object_name ()

+
guint
+ostree_hash_object_name (gconstpointer a);
+

Use this function with GHashTable and ostree_object_name_serialize().

+
+

Parameters

+
+++++ + + + + + +

a

A GVariant containing a serialized object

 
+
+
+
+
+

ostree_object_name_serialize ()

+
GVariant *
+ostree_object_name_serialize (const char *checksum,
+                              OstreeObjectType objtype);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

checksum

An ASCII checksum

 

objtype

An object type

 
+
+
+

Returns

+

A new floating GVariant containing checksum string and objtype.

+

[transfer floating]

+
+
+
+
+

ostree_object_name_deserialize ()

+
void
+ostree_object_name_deserialize (GVariant *variant,
+                                const char **out_checksum,
+                                OstreeObjectType *out_objtype);
+

Reverse ostree_object_name_serialize(). Note that out_checksum + is +only valid for the lifetime of variant +, and must not be freed.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

variant

A GVariant of type (su)

 

out_checksum

Pointer into string memory of variant +with checksum.

[out][transfer none]

out_objtype

Return object type.

[out]
+
+
+
+
+

ostree_object_to_string ()

+
char *
+ostree_object_to_string (const char *checksum,
+                         OstreeObjectType objtype);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

checksum

An ASCII checksum

 

objtype

Object type

 
+
+
+

Returns

+

A string containing both checksum +and a stringifed version of objtype +

+
+
+
+
+

ostree_object_from_string ()

+
void
+ostree_object_from_string (const char *str,
+                           gchar **out_checksum,
+                           OstreeObjectType *out_objtype);
+

Reverse ostree_object_to_string().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

str

An ASCII checksum

 

out_checksum

Parsed checksum.

[out][transfer full]

out_objtype

Parsed object type.

[out]
+
+
+
+
+

ostree_content_stream_parse ()

+
gboolean
+ostree_content_stream_parse (gboolean compressed,
+                             GInputStream *input,
+                             guint64 input_length,
+                             gboolean trusted,
+                             GInputStream **out_input,
+                             GFileInfo **out_file_info,
+                             GVariant **out_xattrs,
+                             GCancellable *cancellable,
+                             GError **error);
+

The reverse of ostree_raw_file_to_content_stream(); this function +converts an object content stream back into components.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

compressed

Whether or not the stream is zlib-compressed

 

input

Object content stream

 

input_length

Length of stream

 

trusted

If TRUE, assume the content has been validated

 

out_input

The raw file content stream.

[out]

out_file_info

Normal metadata.

[out]

out_xattrs

Extended attributes.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_content_file_parse ()

+
gboolean
+ostree_content_file_parse (gboolean compressed,
+                           GFile *content_path,
+                           gboolean trusted,
+                           GInputStream **out_input,
+                           GFileInfo **out_file_info,
+                           GVariant **out_xattrs,
+                           GCancellable *cancellable,
+                           GError **error);
+

A thin wrapper for ostree_content_stream_parse(); this function +converts an object content stream back into components.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

compressed

Whether or not the stream is zlib-compressed

 

content_path

Path to file containing content

 

trusted

If TRUE, assume the content has been validated

 

out_input

The raw file content stream.

[out]

out_file_info

Normal metadata.

[out]

out_xattrs

Extended attributes.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_content_file_parse_at ()

+
gboolean
+ostree_content_file_parse_at (gboolean compressed,
+                              int parent_dfd,
+                              const char *path,
+                              gboolean trusted,
+                              GInputStream **out_input,
+                              GFileInfo **out_file_info,
+                              GVariant **out_xattrs,
+                              GCancellable *cancellable,
+                              GError **error);
+

A thin wrapper for ostree_content_stream_parse(); this function +converts an object content stream back into components.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

compressed

Whether or not the stream is zlib-compressed

 

parent_dfd

Directory file descriptor

 

path

Subpath

 

trusted

If TRUE, assume the content has been validated

 

out_input

The raw file content stream.

[out]

out_file_info

Normal metadata.

[out]

out_xattrs

Extended attributes.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_raw_file_to_archive_z2_stream ()

+
gboolean
+ostree_raw_file_to_archive_z2_stream (GInputStream *input,
+                                      GFileInfo *file_info,
+                                      GVariant *xattrs,
+                                      GInputStream **out_input,
+                                      GCancellable *cancellable,
+                                      GError **error);
+

Convert from a "bare" file representation into an +OSTREE_OBJECT_TYPE_FILE stream suitable for ostree pull.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

input

File raw content stream

 

file_info

A file info

 

xattrs

Optional extended attributes.

[allow-none]

out_input

Serialized object stream.

[out]

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2016.6

+
+
+
+

ostree_raw_file_to_archive_z2_stream_with_options ()

+
gboolean
+ostree_raw_file_to_archive_z2_stream_with_options
+                               (GInputStream *input,
+                                GFileInfo *file_info,
+                                GVariant *xattrs,
+                                GVariant *options,
+                                GInputStream **out_input,
+                                GCancellable *cancellable,
+                                GError **error);
+

Like ostree_raw_file_to_archive_z2_stream(), but supports an extensible set +of flags. The following flags are currently defined:

+
  • compression-level (i): Level of compression to use, 0–9, with 0 being +the least compression, and <0 giving the default level (currently 6).

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

input

File raw content stream

 

file_info

A file info

 

xattrs

Optional extended attributes.

[allow-none]

options

A GVariant a{sv} with an extensible set of flags.

[nullable]

out_input

Serialized object stream.

[out]

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2017.3

+
+
+
+

ostree_raw_file_to_content_stream ()

+
gboolean
+ostree_raw_file_to_content_stream (GInputStream *input,
+                                   GFileInfo *file_info,
+                                   GVariant *xattrs,
+                                   GInputStream **out_input,
+                                   guint64 *out_length,
+                                   GCancellable *cancellable,
+                                   GError **error);
+

Convert from a "bare" file representation into an +OSTREE_OBJECT_TYPE_FILE stream. This is a fundamental operation +for writing data to an OstreeRepo.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

input

File raw content stream

 

file_info

A file info

 

xattrs

Optional extended attributes.

[allow-none]

out_input

Serialized object stream.

[out]

out_length

Length of stream.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_break_hardlink ()

+
gboolean
+ostree_break_hardlink (int dfd,
+                       const char *path,
+                       gboolean skip_xattrs,
+                       GCancellable *cancellable,
+                       GError **error);
+

In many cases using libostree, a program may need to "break" +hardlinks by performing a copy. For example, in order to +logically append to a file.

+

This function performs full copying, including e.g. extended +attributes and permissions of both regular files and symbolic links.

+

If the file is not hardlinked, this function does nothing and +returns successfully.

+

This function does not perform synchronization via fsync() or +fdatasync(); the idea is this will commonly be done as part +of an ostree_repo_commit_transaction(), which itself takes +care of synchronization.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

dfd

Directory fd

 

path

Path relative to dfd +

 

skip_xattrs

Do not copy extended attributes

 

error

error

 
+
+

Since: 2017.15

+
+
+
+

ostree_checksum_file_from_input ()

+
gboolean
+ostree_checksum_file_from_input (GFileInfo *file_info,
+                                 GVariant *xattrs,
+                                 GInputStream *in,
+                                 OstreeObjectType objtype,
+                                 guchar **out_csum,
+                                 GCancellable *cancellable,
+                                 GError **error);
+

Compute the OSTree checksum for a given input.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

file_info

File information

 

xattrs

Optional extended attributes.

[allow-none]

in

File content, should be NULL for symbolic links.

[allow-none]

objtype

Object type

 

out_csum

Return location for binary checksum.

[out][array fixed-size=32]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_checksum_file ()

+
gboolean
+ostree_checksum_file (GFile *f,
+                      OstreeObjectType objtype,
+                      guchar **out_csum,
+                      GCancellable *cancellable,
+                      GError **error);
+

Compute the OSTree checksum for a given file.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

f

File path

 

objtype

Object type

 

out_csum

Return location for binary checksum.

[out][array fixed-size=32]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_checksum_file_at ()

+
gboolean
+ostree_checksum_file_at (int dfd,
+                         const char *path,
+                         struct stat *stbuf,
+                         OstreeObjectType objtype,
+                         OstreeChecksumFlags flags,
+                         char **out_checksum,
+                         GCancellable *cancellable,
+                         GError **error);
+

Compute the OSTree checksum for a given file. This is an fd-relative version +of ostree_checksum_file() which also takes flags and fills in a caller +allocated buffer.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

dfd

Directory file descriptor

 

path

Subpath

 

stbuf (allow-none)

Optional stat buffer

 

objtype

Object type

 

flags

Flags

 

out_checksum (out) (transfer full)

Return location for hex checksum

 

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2017.13

+
+
+
+

ostree_checksum_file_async ()

+
void
+ostree_checksum_file_async (GFile *f,
+                            OstreeObjectType objtype,
+                            int io_priority,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data);
+

Asynchronously compute the OSTree checksum for a given file; +complete with ostree_checksum_file_async_finish().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

f

File path

 

objtype

Object type

 

io_priority

Priority for operation, see G_IO_PRIORITY_DEFAULT

 

cancellable

Cancellable

 

callback

Invoked when operation is complete

 

user_data

Data for callback +

 
+
+
+
+
+

ostree_checksum_file_async_finish ()

+
gboolean
+ostree_checksum_file_async_finish (GFile *f,
+                                   GAsyncResult *result,
+                                   guchar **out_csum,
+                                   GError **error);
+

Finish computing the OSTree checksum for a given file; see +ostree_checksum_file_async().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

f

File path

 

result

Async result

 

out_csum

Return location for binary checksum.

[out][array fixed-size=32]

error

Error

 
+
+
+
+
+

ostree_create_directory_metadata ()

+
GVariant *
+ostree_create_directory_metadata (GFileInfo *dir_info,
+                                  GVariant *xattrs);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

dir_info

a GFileInfo containing directory information

 

xattrs

Optional extended attributes.

[allow-none]
+
+
+

Returns

+

A new GVariant containing OSTREE_OBJECT_TYPE_DIR_META.

+

[transfer full]

+
+
+
+
+

ostree_validate_structureof_objtype ()

+
gboolean
+ostree_validate_structureof_objtype (guchar objtype,
+                                     GError **error);
+
+

Parameters

+
+++++ + + + + + +

error

Error

 
+
+
+

Returns

+

TRUE if objtype +represents a valid object type

+
+
+
+
+

ostree_validate_structureof_csum_v ()

+
gboolean
+ostree_validate_structureof_csum_v (GVariant *checksum,
+                                    GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

checksum

a GVariant of type "ay"

 

error

Error

 
+
+
+

Returns

+

TRUE if checksum +is a valid binary SHA256 checksum

+
+
+
+
+

ostree_validate_structureof_checksum_string ()

+
gboolean
+ostree_validate_structureof_checksum_string
+                               (const char *checksum,
+                                GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

checksum

an ASCII string

 

error

Error

 
+
+
+

Returns

+

TRUE if checksum +is a valid ASCII SHA256 checksum

+
+
+
+
+

ostree_validate_structureof_file_mode ()

+
gboolean
+ostree_validate_structureof_file_mode (guint32 mode,
+                                       GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

mode

A Unix filesystem mode

 

error

Error

 
+
+
+

Returns

+

TRUE if mode +represents a valid file type and permissions

+
+
+
+
+

ostree_validate_structureof_commit ()

+
gboolean
+ostree_validate_structureof_commit (GVariant *commit,
+                                    GError **error);
+

Use this to validate the basic structure of commit +, independent of +any other objects it references.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

commit

A commit object, OSTREE_OBJECT_TYPE_COMMIT

 

error

Error

 
+
+
+

Returns

+

TRUE if commit +is structurally valid

+
+
+
+
+

ostree_validate_structureof_dirtree ()

+
gboolean
+ostree_validate_structureof_dirtree (GVariant *dirtree,
+                                     GError **error);
+

Use this to validate the basic structure of dirtree +, independent of +any other objects it references.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

dirtree

A dirtree object, OSTREE_OBJECT_TYPE_DIR_TREE

 

error

Error

 
+
+
+

Returns

+

TRUE if dirtree +is structurally valid

+
+
+
+
+

ostree_validate_structureof_dirmeta ()

+
gboolean
+ostree_validate_structureof_dirmeta (GVariant *dirmeta,
+                                     GError **error);
+

Use this to validate the basic structure of dirmeta +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

dirmeta

A dirmeta object, OSTREE_OBJECT_TYPE_DIR_META

 

error

Error

 
+
+
+

Returns

+

TRUE if dirmeta +is structurally valid

+
+
+
+
+

ostree_commit_get_parent ()

+
gchar *
+ostree_commit_get_parent (GVariant *commit_variant);
+
+

Parameters

+
+++++ + + + + + +

commit_variant

Variant of type OSTREE_OBJECT_TYPE_COMMIT

 
+
+
+

Returns

+

Checksum of the parent commit of commit_variant +, or NULL +if none

+
+
+
+
+

ostree_commit_get_timestamp ()

+
guint64
+ostree_commit_get_timestamp (GVariant *commit_variant);
+
+

Parameters

+
+++++ + + + + + +

commit_variant

Commit object

 
+
+
+

Returns

+

timestamp in seconds since the Unix epoch, UTC

+
+

Since: 2016.3

+
+
+
+

ostree_commit_get_content_checksum ()

+
gchar *
+ostree_commit_get_content_checksum (GVariant *commit_variant);
+

There are use cases where one wants a checksum just of the content of a +commit. OSTree commits by default capture the current timestamp, and may have +additional metadata, which means that re-committing identical content +often results in a new checksum.

+

By comparing checksums of content, it's possible to easily distinguish +cases where nothing actually changed.

+

The content checksums is simply defined as SHA256(root dirtree_checksum || root_dirmeta_checksum), +i.e. the SHA-256 of the root "dirtree" object's checksum concatenated with the +root "dirmeta" checksum (both in binary form, not hexadecimal).

+
+

Parameters

+
+++++ + + + + + +

commit_variant

A commit object

 
+
+
+

Returns

+

A SHA-256 hex string, or NULL if commit_variant +is not well-formed.

+

[nullable]

+
+

Since: 2018.2

+
+
+
+

ostree_commit_get_object_sizes ()

+
gboolean
+ostree_commit_get_object_sizes (GVariant *commit_variant,
+                                GPtrArray **out_sizes_entries,
+                                GError **error);
+

Reads a commit's "ostree.sizes" metadata and returns an array of +OstreeCommitSizesEntry in out_sizes_entries +. Each element +represents an object in the commit. If the commit does not contain +the "ostree.sizes" metadata, a G_IO_ERROR_NOT_FOUND error will be +returned.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

commit_variant

variant of type OSTREE_OBJECT_TYPE_COMMIT.

[not nullable]

out_sizes_entries

return location for an array of object size entries.

[out][element-type OstreeCommitSizesEntry][transfer container][optional]

error

Error

 
+
+

Since: 2020.1

+
+
+
+

ostree_commit_sizes_entry_new ()

+
OstreeCommitSizesEntry *
+ostree_commit_sizes_entry_new (const gchar *checksum,
+                               OstreeObjectType objtype,
+                               guint64 unpacked,
+                               guint64 archived);
+

Create a new OstreeCommitSizesEntry for representing an object in a +commit's "ostree.sizes" metadata.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

checksum

object checksum.

[not nullable]

objtype

object type

 

unpacked

unpacked object size

 

archived

compressed object size

 
+
+ +

Since: 2020.1

+
+
+
+

ostree_commit_sizes_entry_copy ()

+
OstreeCommitSizesEntry *
+ostree_commit_sizes_entry_copy (const OstreeCommitSizesEntry *entry);
+

Create a copy of the given entry +.

+
+

Parameters

+
+++++ + + + + + +

entry

an OstreeCommitSizesEntry.

[not nullable]
+
+
+

Returns

+

a new copy of entry +.

+

[transfer full][nullable]

+
+

Since: 2020.1

+
+
+
+

ostree_commit_sizes_entry_free ()

+
void
+ostree_commit_sizes_entry_free (OstreeCommitSizesEntry *entry);
+

Free given entry +.

+
+

Parameters

+
+++++ + + + + + +

entry

an OstreeCommitSizesEntry.

[transfer full]
+
+

Since: 2020.1

+
+
+
+

ostree_check_version ()

+
gboolean
+ostree_check_version (guint required_year,
+                      guint required_release);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

required_year

Major/year required

 

required_release

Release version required

 
+
+
+

Returns

+

TRUE if current libostree has at least the requested version, FALSE otherwise

+
+

Since: 2017.4

+
+
+
+

Types and Values

+
+

OSTREE_MAX_METADATA_SIZE

+
#define OSTREE_MAX_METADATA_SIZE (10 * 1024 * 1024)
+
+

Default limit for maximum permitted size in bytes of metadata objects fetched +over HTTP (including repo/config files, refs, and commit/dirtree/dirmeta +objects). This is an arbitrary number intended to mitigate disk space +exhaustion attacks.

+
+
+
+

OSTREE_MAX_METADATA_WARN_SIZE

+
#define OSTREE_MAX_METADATA_WARN_SIZE (7 * 1024 * 1024)
+
+

This variable is no longer meaningful, it is kept only for compatibility.

+
+
+
+

enum OstreeObjectType

+

Enumeration for core object types; OSTREE_OBJECT_TYPE_FILE is for +content, the other types are metadata.

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_OBJECT_TYPE_FILE

+

Content; regular file, symbolic link

+
 

OSTREE_OBJECT_TYPE_DIR_TREE

+

List of children (trees or files), and metadata

+
 

OSTREE_OBJECT_TYPE_DIR_META

+

Directory metadata

+
 

OSTREE_OBJECT_TYPE_COMMIT

+

Toplevel object, refers to tree and dirmeta for root

+
 

OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT

+

Toplevel object, refers to a deleted commit

+
 

OSTREE_OBJECT_TYPE_COMMIT_META

+

Detached metadata for a commit

+
 

OSTREE_OBJECT_TYPE_PAYLOAD_LINK

+

Symlink to a .file given its checksum on the payload only.

+
 
+
+
+
+
+

OSTREE_OBJECT_TYPE_LAST

+
#define OSTREE_OBJECT_TYPE_LAST OSTREE_OBJECT_TYPE_PAYLOAD_LINK
+
+

Last valid object type; use this to validate ranges.

+
+
+
+

OSTREE_DIRMETA_GVARIANT_STRING

+
#define OSTREE_DIRMETA_GVARIANT_STRING "(uuua(ayay))"
+
+
+
+
+

OSTREE_DIRMETA_GVARIANT_FORMAT

+
#define OSTREE_DIRMETA_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_DIRMETA_GVARIANT_STRING)
+
+
    +
  • u - uid (big-endian)

  • +
  • u - gid (big-endian)

  • +
  • u - mode (big-endian)

  • +
  • a(ayay) - xattrs

  • +
+
+
+
+

OSTREE_FILEMETA_GVARIANT_STRING

+
#define OSTREE_FILEMETA_GVARIANT_STRING "(uuua(ayay))"
+
+
+
+
+

OSTREE_FILEMETA_GVARIANT_FORMAT

+
#define OSTREE_FILEMETA_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_FILEMETA_GVARIANT_STRING)
+
+

This is not a regular object type, but used as an xattr on a .file object +in bare-user repositories. This allows us to store metadata information that we +can't store in the real filesystem but we can still use a regular .file object +that we can hardlink to in the case of a user-mode checkout.

+
    +
  • u - uid (big-endian)

  • +
  • u - gid (big-endian)

  • +
  • u - mode (big-endian)

  • +
  • a(ayay) - xattrs

  • +
+
+
+
+

OSTREE_TREE_GVARIANT_STRING

+
#define OSTREE_TREE_GVARIANT_STRING "(a(say)a(sayay))"
+
+
+
+
+

OSTREE_TREE_GVARIANT_FORMAT

+
#define OSTREE_TREE_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_TREE_GVARIANT_STRING)
+
+
    +
  • a(say) - array of (filename, checksum) for files

  • +
  • a(sayay) - array of (dirname, tree_checksum, meta_checksum) for directories

  • +
+
+
+
+

OSTREE_COMMIT_GVARIANT_STRING

+
#define OSTREE_COMMIT_GVARIANT_STRING "(a{sv}aya(say)sstayay)"
+
+
+
+
+

OSTREE_COMMIT_GVARIANT_FORMAT

+
#define OSTREE_COMMIT_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_COMMIT_GVARIANT_STRING)
+
+
    +
  • a{sv} - Metadata

  • +
  • ay - parent checksum (empty string for initial)

  • +
  • a(say) - Related objects

  • +
  • s - subject

  • +
  • s - body

  • +
  • t - Timestamp in seconds since the epoch (UTC, big-endian)

  • +
  • ay - Root tree contents

  • +
  • ay - Root tree metadata

  • +
+
+
+
+

OSTREE_SUMMARY_GVARIANT_STRING

+
#define OSTREE_SUMMARY_GVARIANT_STRING "(a(s(taya{sv}))a{sv})"
+
+
+
+
+

OSTREE_SUMMARY_GVARIANT_FORMAT

+
#define OSTREE_SUMMARY_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_SUMMARY_GVARIANT_STRING)
+
+
    +
  • a(s(taya{sv})) - Map of ref name -> (latest commit size, latest commit checksum, additional metadata), sorted by ref name

  • +
  • +

    a{sv} - Additional metadata, at the current time the following are defined:

    +
      +
    • key: "ostree.static-deltas", value: a{sv}, static delta name -> 32 bytes of checksum

    • +
    • key: "ostree.summary.last-modified", value: t, timestamp (seconds since +the Unix epoch in UTC, big-endian) when the summary was last regenerated +(similar to the HTTP Last-Modified header)

    • +
    • key: "ostree.summary.expires", value: t, timestamp (seconds since the +Unix epoch in UTC, big-endian) after which the summary is considered +stale and should be re-downloaded if possible (similar to the HTTP +Expires header)

    • +
    +
  • +
+

The currently defined keys for the a{sv} of additional metadata for each commit are:

+
  • key: ostree.commit.timestamp, value: t, timestamp (seconds since the +Unix epoch in UTC, big-endian) when the commit was committed

+
+
+
+

OstreeCommitSizesEntry

+
typedef struct {
+  gchar *checksum;
+  OstreeObjectType objtype;
+  guint64 unpacked;
+  guint64 archived;
+} OstreeCommitSizesEntry;
+
+

Structure representing an entry in the "ostree.sizes" commit metadata. Each +entry corresponds to an object in the associated commit.

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

gchar *checksum;

object checksum.

[not nullable]

OstreeObjectType objtype;

object type

 

guint64 unpacked;

unpacked object size

 

guint64 archived;

compressed object size

 
+
+

Since: 2020.1

+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-GPG-signature-verification-results.html b/apidoc/html/ostree-GPG-signature-verification-results.html new file mode 100644 index 0000000..9cd9c4c --- /dev/null +++ b/apidoc/html/ostree-GPG-signature-verification-results.html @@ -0,0 +1,754 @@ + + + + +GPG signature verification results: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

GPG signature verification results

+

GPG signature verification results — Inspect detached GPG signatures

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+guint + +ostree_gpg_verify_result_count_all () +
+guint + +ostree_gpg_verify_result_count_valid () +
+gboolean + +ostree_gpg_verify_result_lookup () +
+GVariant * + +ostree_gpg_verify_result_get () +
+GVariant * + +ostree_gpg_verify_result_get_all () +
+void + +ostree_gpg_verify_result_describe () +
+void + +ostree_gpg_verify_result_describe_variant () +
+gboolean + +ostree_gpg_verify_result_require_valid_signature () +
+
+
+

Types and Values

+
++++ + + + + + + + + + + + + + + + + + + +
enumOstreeGpgError
typedefOstreeGpgVerifyResult
enumOstreeGpgSignatureAttr
enumOstreeGpgSignatureFormatFlags
+
+
+

Description

+

OstreeGpgVerifyResult contains verification details for GPG signatures +read from a detached OstreeRepo metadata object.

+

Use ostree_gpg_verify_result_count_all() and +ostree_gpg_verify_result_count_valid() to quickly check overall signature +validity.

+

Use ostree_gpg_verify_result_lookup() to find a signature by the key ID +or fingerprint of the signing key.

+

For more in-depth inspection, such as presenting signature details to the +user, pass an array of attribute values to ostree_gpg_verify_result_get() +or get all signature details with ostree_gpg_verify_result_get_all().

+
+
+

Functions

+
+

ostree_gpg_verify_result_count_all ()

+
guint
+ostree_gpg_verify_result_count_all (OstreeGpgVerifyResult *result);
+

Counts all the signatures in result +.

+
+

Parameters

+
+++++ + + + + + +

result

an OstreeGpgVerifyResult

 
+
+
+

Returns

+

signature count

+
+
+
+
+

ostree_gpg_verify_result_count_valid ()

+
guint
+ostree_gpg_verify_result_count_valid (OstreeGpgVerifyResult *result);
+

Counts only the valid signatures in result +.

+
+

Parameters

+
+++++ + + + + + +

result

an OstreeGpgVerifyResult

 
+
+
+

Returns

+

valid signature count

+
+
+
+
+

ostree_gpg_verify_result_lookup ()

+
gboolean
+ostree_gpg_verify_result_lookup (OstreeGpgVerifyResult *result,
+                                 const gchar *key_id,
+                                 guint *out_signature_index);
+

Searches result + for a signature signed by key_id +. If a match is found, +the function returns TRUE and sets out_signature_index + so that further +signature details can be obtained through ostree_gpg_verify_result_get(). +If no match is found, the function returns FALSE and leaves +out_signature_index + unchanged.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

result

an OstreeGpgVerifyResult

 

key_id

a GPG key ID or fingerprint

 

out_signature_index

return location for the index of the signature +signed by key_id +, or NULL.

[out]
+
+
+

Returns

+

TRUE on success, FALSE on failure

+
+
+
+
+

ostree_gpg_verify_result_get ()

+
GVariant *
+ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result,
+                              guint signature_index,
+                              OstreeGpgSignatureAttr *attrs,
+                              guint n_attrs);
+

Builds a GVariant tuple of requested attributes for the GPG signature at +signature_index + in result +. See the OstreeGpgSignatureAttr description +for the GVariantType of each available attribute.

+

It is a programmer error to request an invalid OstreeGpgSignatureAttr or +an invalid signature_index +. Use ostree_gpg_verify_result_count_all() to +find the number of signatures in result +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

result

an OstreeGpgVerifyResult

 

signature_index

which signature to get attributes from

 

attrs

Array of requested attributes.

[array length=n_attrs]

n_attrs

Length of the attrs +array

 
+
+
+

Returns

+

a new, floating, GVariant tuple

+
+
+
+
+

ostree_gpg_verify_result_get_all ()

+
GVariant *
+ostree_gpg_verify_result_get_all (OstreeGpgVerifyResult *result,
+                                  guint signature_index);
+

Builds a GVariant tuple of all available attributes for the GPG signature +at signature_index + in result +.

+

The child values in the returned GVariant tuple are ordered to match the +OstreeGpgSignatureAttr enumeration, which means the enum values can be +used as index values in functions like g_variant_get_child(). See the +OstreeGpgSignatureAttr description for the GVariantType of each +available attribute.

+

+ The OstreeGpgSignatureAttr enumeration may be extended in the future + with new attributes, which would affect the GVariant tuple returned by + this function. While the position and type of current child values in + the GVariant tuple will not change, to avoid backward-compatibility + issues please do not depend on the tuple's overall size or + type signature. +

+

It is a programmer error to request an invalid signature_index +. Use +ostree_gpg_verify_result_count_all() to find the number of signatures in +result +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

result

an OstreeGpgVerifyResult

 

signature_index

which signature to get attributes from

 
+
+
+

Returns

+

a new, floating, GVariant tuple

+
+
+
+
+

ostree_gpg_verify_result_describe ()

+
void
+ostree_gpg_verify_result_describe (OstreeGpgVerifyResult *result,
+                                   guint signature_index,
+                                   GString *output_buffer,
+                                   const gchar *line_prefix,
+                                   OstreeGpgSignatureFormatFlags flags);
+

Appends a brief, human-readable description of the GPG signature at +signature_index + in result + to the output_buffer +. The description +spans multiple lines. A line_prefix + string, if given, will precede +each line of the description.

+

The flags + argument is reserved for future variations to the description +format. Currently must be 0.

+

It is a programmer error to request an invalid signature_index +. Use +ostree_gpg_verify_result_count_all() to find the number of signatures in +result +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

result

an OstreeGpgVerifyResult

 

signature_index

which signature to describe

 

output_buffer

a GString to hold the description

 

line_prefix

optional line prefix string.

[allow-none]

flags

flags to adjust the description format

 
+
+
+
+
+

ostree_gpg_verify_result_describe_variant ()

+
void
+ostree_gpg_verify_result_describe_variant
+                               (GVariant *variant,
+                                GString *output_buffer,
+                                const gchar *line_prefix,
+                                OstreeGpgSignatureFormatFlags flags);
+

Similar to ostree_gpg_verify_result_describe() but takes a GVariant of +all attributes for a GPG signature instead of an OstreeGpgVerifyResult +and signature index.

+

The variant + MUST have been created by +ostree_gpg_verify_result_get_all().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

variant

a GVariant from ostree_gpg_verify_result_get_all()

 

output_buffer

a GString to hold the description

 

line_prefix

optional line prefix string.

[allow-none]

flags

flags to adjust the description format

 
+
+
+
+
+

ostree_gpg_verify_result_require_valid_signature ()

+
gboolean
+ostree_gpg_verify_result_require_valid_signature
+                               (OstreeGpgVerifyResult *result,
+                                GError **error);
+

Checks if the result contains at least one signature from the +trusted keyring. You can call this function immediately after +ostree_repo_verify_summary() or ostree_repo_verify_commit_ext() - +it will handle the NULL result + and filled error + too.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

result

an OstreeGpgVerifyResult.

[nullable]

error

A GError

 
+
+
+

Returns

+

TRUE if result +was not NULL and had at least one +signature from trusted keyring, otherwise FALSE

+
+

Since: 2016.6

+
+
+
+

Types and Values

+
+

enum OstreeGpgError

+

Errors returned by signature creation and verification operations in OSTree. +These may be returned by any API which creates or verifies signatures.

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_GPG_ERROR_NO_SIGNATURE

+

A signature was expected, but not found.

+
 

OSTREE_GPG_ERROR_INVALID_SIGNATURE

+

A signature was malformed.

+
 

OSTREE_GPG_ERROR_MISSING_KEY

+

A signature was found, but was created with a key not in the configured keyrings.

+
 

OSTREE_GPG_ERROR_EXPIRED_SIGNATURE

+

A signature was expired. Since: 2020.1.

+
 

OSTREE_GPG_ERROR_EXPIRED_KEY

+

A signature was found, but the key used to +sign it has expired. Since: 2020.1.

+
 

OSTREE_GPG_ERROR_REVOKED_KEY

+

A signature was found, but the key used to +sign it has been revoked. Since: 2020.1.

+
 
+
+

Since: 2017.10

+
+
+
+

OstreeGpgVerifyResult

+
typedef struct OstreeGpgVerifyResult OstreeGpgVerifyResult;
+
+

Private instance structure.

+
+
+
+

enum OstreeGpgSignatureAttr

+

Signature attributes available from an OstreeGpgVerifyResult. +The attribute's GVariantType is shown in brackets.

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_GPG_SIGNATURE_ATTR_VALID

+

[G_VARIANT_TYPE_BOOLEAN] Is the signature valid?

+
 

OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED

+

[G_VARIANT_TYPE_BOOLEAN] Has the signature expired?

+
 

OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED

+

[G_VARIANT_TYPE_BOOLEAN] Has the signing key expired?

+
 

OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED

+

[G_VARIANT_TYPE_BOOLEAN] Has the signing key been revoked?

+
 

OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING

+

[G_VARIANT_TYPE_BOOLEAN] Is the signing key missing?

+
 

OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT

+

[G_VARIANT_TYPE_STRING] Fingerprint of the signing key

+
 

OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP

+

[G_VARIANT_TYPE_INT64] Signature creation Unix timestamp

+
 

OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP

+

[G_VARIANT_TYPE_INT64] Signature expiration Unix timestamp (0 if no +expiration)

+
 

OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME

+

[G_VARIANT_TYPE_STRING] Name of the public key algorithm used to create +the signature

+
 

OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME

+

[G_VARIANT_TYPE_STRING] Name of the hash algorithm used to create the +signature

+
 

OSTREE_GPG_SIGNATURE_ATTR_USER_NAME

+

[G_VARIANT_TYPE_STRING] The name of the signing key's primary user

+
 

OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL

+

[G_VARIANT_TYPE_STRING] The email address of the signing key's primary +user

+
 

OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY

+

[G_VARIANT_TYPE_STRING] Fingerprint of the signing key's primary key +(will be the same as OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT if the +the signature is already from the primary key rather than a subkey, +and will be the empty string if the key is missing.)

+
 

OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP

+

[G_VARIANT_TYPE_INT64] Key expiration Unix timestamp (0 if no +expiration or if the key is missing)

+
 

OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP_PRIMARY

+

[G_VARIANT_TYPE_INT64] Key expiration Unix timestamp of the signing key's +primary key (will be the same as OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP +if the signing key is the primary key and 0 if no expiration or if the key +is missing)

+
 
+
+
+
+
+

enum OstreeGpgSignatureFormatFlags

+

Formatting flags for ostree_gpg_verify_result_describe(). Currently +there's only one possible output format, but this enumeration allows +for future variations.

+
+

Members

+
+++++ + + + + + +

OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT

+

Use the default output format

+
 
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html b/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html new file mode 100644 index 0000000..1f109bb --- /dev/null +++ b/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html @@ -0,0 +1,627 @@ + + + + +In-memory modifiable filesystem tree: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

In-memory modifiable filesystem tree

+

In-memory modifiable filesystem tree — Modifiable filesystem tree

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+OstreeMutableTree * + +ostree_mutable_tree_new () +
+OstreeMutableTree * + +ostree_mutable_tree_new_from_checksum () +
+gboolean + +ostree_mutable_tree_check_error () +
+void + +ostree_mutable_tree_set_metadata_checksum () +
const char * + +ostree_mutable_tree_get_metadata_checksum () +
+void + +ostree_mutable_tree_set_contents_checksum () +
const char * + +ostree_mutable_tree_get_contents_checksum () +
+gboolean + +ostree_mutable_tree_replace_file () +
+gboolean + +ostree_mutable_tree_remove () +
+gboolean + +ostree_mutable_tree_ensure_dir () +
+gboolean + +ostree_mutable_tree_lookup () +
+gboolean + +ostree_mutable_tree_ensure_parent_dirs () +
+gboolean + +ostree_mutable_tree_walk () +
+GHashTable * + +ostree_mutable_tree_get_subdirs () +
+GHashTable * + +ostree_mutable_tree_get_files () +
+gboolean + +ostree_mutable_tree_fill_empty_from_dirtree () +
+
+
+

Types and Values

+
++++ + + + + +
typedefOstreeMutableTree
+
+
+

Description

+

In order to commit content into an OstreeRepo, it must first be +imported into an OstreeMutableTree. There are several high level +APIs to create an initiable OstreeMutableTree from a physical +filesystem directory, but they may also be computed +programmatically.

+
+
+

Functions

+
+

ostree_mutable_tree_new ()

+
OstreeMutableTree *
+ostree_mutable_tree_new (void);
+
+

Returns

+

A new tree.

+

[transfer full]

+
+
+
+
+

ostree_mutable_tree_new_from_checksum ()

+
OstreeMutableTree *
+ostree_mutable_tree_new_from_checksum (OstreeRepo *repo,
+                                       const char *contents_checksum,
+                                       const char *metadata_checksum);
+

Creates a new OstreeMutableTree with the contents taken from the given repo +and checksums. The data will be loaded from the repo lazily as needed.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

repo

The repo which contains the objects refered by the checksums.

 

contents_checksum

dirtree checksum

 

metadata_checksum

dirmeta checksum

 
+
+
+

Returns

+

A new tree.

+

[transfer full]

+
+

Since: 2018.7

+
+
+
+

ostree_mutable_tree_check_error ()

+
gboolean
+ostree_mutable_tree_check_error (OstreeMutableTree *self,
+                                 GError **error);
+

In some cases, a tree may be in a "lazy" state that loads +data in the background; if an error occurred during a non-throwing +API call, it will have been cached. This function checks for a +cached error. The tree remains in error state.

+
+

Parameters

+
+++++ + + + + + +

self

Tree

 
+
+
+

Returns

+

TRUE on success

+
+

Since: 2018.7

+
+
+
+

ostree_mutable_tree_set_metadata_checksum ()

+
void
+ostree_mutable_tree_set_metadata_checksum
+                               (OstreeMutableTree *self,
+                                const char *checksum);
+
+
+
+

ostree_mutable_tree_get_metadata_checksum ()

+
const char *
+ostree_mutable_tree_get_metadata_checksum
+                               (OstreeMutableTree *self);
+
+
+
+

ostree_mutable_tree_set_contents_checksum ()

+
void
+ostree_mutable_tree_set_contents_checksum
+                               (OstreeMutableTree *self,
+                                const char *checksum);
+
+
+
+

ostree_mutable_tree_get_contents_checksum ()

+
const char *
+ostree_mutable_tree_get_contents_checksum
+                               (OstreeMutableTree *self);
+
+
+
+

ostree_mutable_tree_replace_file ()

+
gboolean
+ostree_mutable_tree_replace_file (OstreeMutableTree *self,
+                                  const char *name,
+                                  const char *checksum,
+                                  GError **error);
+
+
+
+

ostree_mutable_tree_remove ()

+
gboolean
+ostree_mutable_tree_remove (OstreeMutableTree *self,
+                            const char *name,
+                            gboolean allow_noent,
+                            GError **error);
+

Remove the file or subdirectory named name + from the mutable tree self +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Tree

 

name

Name of file or subdirectory to remove

 

allow_noent

If FALSE +, an error will be thrown if name +does not exist in the tree

 

error

a GError

 
+
+

Since: 2018.9

+
+
+
+

ostree_mutable_tree_ensure_dir ()

+
gboolean
+ostree_mutable_tree_ensure_dir (OstreeMutableTree *self,
+                                const char *name,
+                                OstreeMutableTree **out_subdir,
+                                GError **error);
+

Returns the subdirectory of self with filename name +, creating an empty one +it if it doesn't exist.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Tree

 

name

Name of subdirectory of self to retrieve/creates

 

out_subdir

the subdirectory.

[out][transfer full]

error

a GError

 
+
+
+
+
+

ostree_mutable_tree_lookup ()

+
gboolean
+ostree_mutable_tree_lookup (OstreeMutableTree *self,
+                            const char *name,
+                            char **out_file_checksum,
+                            OstreeMutableTree **out_subdir,
+                            GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Tree

 

name

name

 

out_file_checksum

checksum.

[out][transfer full]

out_subdir

subdirectory.

[out][transfer full]

error

a GError

 
+
+
+
+
+

ostree_mutable_tree_ensure_parent_dirs ()

+
gboolean
+ostree_mutable_tree_ensure_parent_dirs
+                               (OstreeMutableTree *self,
+                                GPtrArray *split_path,
+                                const char *metadata_checksum,
+                                OstreeMutableTree **out_parent,
+                                GError **error);
+

Create all parent trees necessary for the given split_path + to +exist.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Tree

 

split_path

File path components.

[element-type utf8]

metadata_checksum

SHA256 checksum for metadata

 

out_parent

The parent tree.

[out][transfer full]

error

a GError

 
+
+
+
+
+

ostree_mutable_tree_walk ()

+
gboolean
+ostree_mutable_tree_walk (OstreeMutableTree *self,
+                          GPtrArray *split_path,
+                          guint start,
+                          OstreeMutableTree **out_subdir,
+                          GError **error);
+

Traverse start + number of elements starting from split_path +; the +child will be returned in out_subdir +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Tree

 

split_path

Split pathname.

[element-type utf8]

start

Descend from this number of elements in split_path +

 

out_subdir

Target parent.

[out][transfer full]

error

Error

 
+
+
+
+
+

ostree_mutable_tree_get_subdirs ()

+
GHashTable *
+ostree_mutable_tree_get_subdirs (OstreeMutableTree *self);
+
+

Returns

+

All children directories.

+

[transfer none][element-type utf8 OstreeMutableTree]

+
+
+
+
+

ostree_mutable_tree_get_files ()

+
GHashTable *
+ostree_mutable_tree_get_files (OstreeMutableTree *self);
+
+

Returns

+

All children files (the value is a checksum).

+

[transfer none][element-type utf8 utf8]

+
+
+
+
+

ostree_mutable_tree_fill_empty_from_dirtree ()

+
gboolean
+ostree_mutable_tree_fill_empty_from_dirtree
+                               (OstreeMutableTree *self,
+                                OstreeRepo *repo,
+                                const char *contents_checksum,
+                                const char *metadata_checksum);
+

Merges self + with the tree given by contents_checksum + and +metadata_checksum +, but only if it's possible without writing new objects to +the repo +. We can do this if either self + is empty, the tree given by +contents_checksum + is empty or if both trees already have the same +contents_checksum +.

+
+

Returns

+

TRUE +if merge was successful, FALSE +if it was not possible.

+

This function enables optimisations when composing trees. The provided +checksums are not loaded or checked when this function is called. Instead +the contents will be loaded only when needed.

+
+

Since: 2018.7

+
+
+
+

Types and Values

+
+

OstreeMutableTree

+
typedef struct OstreeMutableTree OstreeMutableTree;
+
+

Private instance structure.

+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-OstreeRepo.html b/apidoc/html/ostree-OstreeRepo.html new file mode 100644 index 0000000..c9a2783 --- /dev/null +++ b/apidoc/html/ostree-OstreeRepo.html @@ -0,0 +1,8875 @@ + + + + +OstreeRepo: Content-addressed object store: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

OstreeRepo: Content-addressed object store

+

OstreeRepo: Content-addressed object store — A git-like storage system for operating system binaries

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+gboolean + +ostree_repo_mode_from_string () +
+OstreeRepo * + +ostree_repo_open_at () +
+OstreeRepo * + +ostree_repo_new () +
+OstreeRepo * + +ostree_repo_new_for_sysroot_path () +
+OstreeRepo * + +ostree_repo_new_default () +
+gboolean + +ostree_repo_open () +
+void + +ostree_repo_set_disable_fsync () +
+gboolean + +ostree_repo_get_disable_fsync () +
+gboolean + +ostree_repo_is_system () +
+gboolean + +ostree_repo_is_writable () +
+OstreeRepo * + +ostree_repo_create_at () +
+gboolean + +ostree_repo_create () +
const gchar * + +ostree_repo_get_bootloader () +
+GFile * + +ostree_repo_get_path () +
+OstreeRepoMode + +ostree_repo_get_mode () +
+gboolean + +ostree_repo_get_min_free_space_bytes () +
+GKeyFile * + +ostree_repo_get_config () +
+int + +ostree_repo_get_dfd () +
const gchar * const * + +ostree_repo_get_default_repo_finders () +
+guint + +ostree_repo_hash () +
+gboolean + +ostree_repo_equal () +
+GKeyFile * + +ostree_repo_copy_config () +
+gboolean + +ostree_repo_remote_add () +
+gboolean + +ostree_repo_remote_delete () +
+gboolean + +ostree_repo_remote_change () +
+char ** + +ostree_repo_remote_list () +
+gboolean + +ostree_repo_remote_get_url () +
+gboolean + +ostree_repo_remote_get_gpg_verify () +
+gboolean + +ostree_repo_remote_get_gpg_verify_summary () +
+gboolean + +ostree_repo_remote_gpg_import () +
+gboolean + +ostree_repo_remote_fetch_summary () +
+gboolean + +ostree_repo_remote_fetch_summary_with_options () +
+gboolean + +ostree_repo_reload_config () +
+gboolean + +ostree_repo_get_remote_boolean_option () +
+gboolean + +ostree_repo_get_remote_list_option () +
+gboolean + +ostree_repo_get_remote_option () +
+OstreeRepo * + +ostree_repo_get_parent () +
+gboolean + +ostree_repo_write_config () +
+gboolean + +ostree_repo_scan_hardlinks () +
+gboolean + +ostree_repo_prepare_transaction () +
+gboolean + +ostree_repo_commit_transaction () +
+gboolean + +ostree_repo_abort_transaction () +
+void + +ostree_repo_transaction_set_refspec () +
+void + +ostree_repo_transaction_set_ref () +
+gboolean + +ostree_repo_set_ref_immediate () +
+gboolean + +ostree_repo_set_alias_ref_immediate () +
+gboolean + +ostree_repo_set_cache_dir () +
+gboolean + +ostree_repo_sign_delta () +
+gboolean + +ostree_repo_has_object () +
+gboolean + +ostree_repo_mark_commit_partial () +
+gboolean + +ostree_repo_mark_commit_partial_reason () +
+gboolean + +ostree_repo_write_metadata () +
+void + +ostree_repo_write_metadata_async () +
+gboolean + +ostree_repo_write_metadata_finish () +
+gboolean + +ostree_repo_write_content () +
+gboolean + +ostree_repo_write_metadata_trusted () +
+gboolean + +ostree_repo_write_metadata_stream_trusted () +
+gboolean + +ostree_repo_write_content_trusted () +
+void + +ostree_repo_write_content_async () +
+gboolean + +ostree_repo_write_content_finish () +
+gboolean + +ostree_repo_resolve_rev () +
+gboolean + +ostree_repo_resolve_rev_ext () +
+gboolean + +ostree_repo_list_refs () +
+gboolean + +ostree_repo_list_refs_ext () +
+gboolean + +ostree_repo_remote_list_refs () +
+gboolean + +ostree_repo_load_variant () +
+gboolean + +ostree_repo_load_commit () +
+gboolean + +ostree_repo_load_variant_if_exists () +
+gboolean + +ostree_repo_load_file () +
+gboolean + +ostree_repo_load_object_stream () +
+gboolean + +ostree_repo_query_object_storage_size () +
+gboolean + +ostree_repo_import_object_from () +
+gboolean + +ostree_repo_import_object_from_with_trust () +
+gboolean + +ostree_repo_import_archive_to_mtree () +
+gboolean + +ostree_repo_export_tree_to_archive () +
+gboolean + +ostree_repo_delete_object () +
+gboolean + +ostree_repo_fsck_object () +
+OstreeRepoCommitFilterResult + +(*OstreeRepoCommitFilter) () +
+OstreeRepoCommitModifier * + +ostree_repo_commit_modifier_new () +
+GVariant * + +(*OstreeRepoCommitModifierXattrCallback) () +
+void + +ostree_repo_commit_modifier_set_xattr_callback () +
+void + +ostree_repo_commit_modifier_set_sepolicy () +
+gboolean + +ostree_repo_commit_modifier_set_sepolicy_from_commit () +
+void + +ostree_repo_commit_modifier_set_devino_cache () +
+OstreeRepoCommitModifier * + +ostree_repo_commit_modifier_ref () +
+void + +ostree_repo_commit_modifier_unref () +
+OstreeRepoDevInoCache * + +ostree_repo_devino_cache_new () +
+OstreeRepoDevInoCache * + +ostree_repo_devino_cache_ref () +
+void + +ostree_repo_devino_cache_unref () +
+GType + +ostree_repo_devino_cache_get_type () +
+gboolean + +ostree_repo_write_directory_to_mtree () +
+gboolean + +ostree_repo_write_dfd_to_mtree () +
+gboolean + +ostree_repo_write_archive_to_mtree () +
+gboolean + +ostree_repo_write_archive_to_mtree_from_fd () +
+gboolean + +ostree_repo_write_mtree () +
+gboolean + +ostree_repo_write_commit () +
+gboolean + +ostree_repo_write_commit_with_time () +
+gboolean + +ostree_repo_read_commit_detached_metadata () +
+gboolean + +ostree_repo_write_commit_detached_metadata () +
+void + +ostree_repo_checkout_at_options_set_devino () +
+gboolean + +ostree_repo_checkout_tree () +
+gboolean + +ostree_repo_checkout_tree_at () +
+gboolean + +ostree_repo_checkout_at () +
+gboolean + +ostree_repo_checkout_gc () +
+gboolean + +ostree_repo_read_commit () +
+gboolean + +ostree_repo_list_objects () +
+gboolean + +ostree_repo_list_commit_objects_starting_with () +
+gboolean + +ostree_repo_list_static_delta_names () +
+gboolean + +ostree_repo_static_delta_generate () +
+gboolean + +ostree_repo_static_delta_execute_offline () +
+GHashTable * + +ostree_repo_traverse_new_reachable () +
+GHashTable * + +ostree_repo_traverse_new_parents () +
+char ** + +ostree_repo_traverse_parents_get_commits () +
+gboolean + +ostree_repo_traverse_commit () +
+gboolean + +ostree_repo_traverse_commit_union () +
+gboolean + +ostree_repo_traverse_commit_union_with_parents () +
+void + +ostree_repo_commit_traverse_iter_cleanup () +
+void + +ostree_repo_commit_traverse_iter_clear () +
+void + +ostree_repo_commit_traverse_iter_get_dir () +
+void + +ostree_repo_commit_traverse_iter_get_file () +
+gboolean + +ostree_repo_commit_traverse_iter_init_commit () +
+gboolean + +ostree_repo_commit_traverse_iter_init_dirtree () +
+OstreeRepoCommitIterResult + +ostree_repo_commit_traverse_iter_next () +
+gboolean + +ostree_repo_prune () +
+gboolean + +ostree_repo_prune_static_deltas () +
+gboolean + +ostree_repo_traverse_reachable_refs () +
+gboolean + +ostree_repo_prune_from_reachable () +
+gboolean + +ostree_repo_pull () +
+gboolean + +ostree_repo_pull_one_dir () +
+gboolean + +ostree_repo_pull_with_options () +
+void + +ostree_repo_pull_default_console_progress_changed () +
+gboolean + +ostree_repo_sign_commit () +
+gboolean + +ostree_repo_append_gpg_signature () +
+gboolean + +ostree_repo_add_gpg_signature_summary () +
+OstreeGpgVerifyResult * + +ostree_repo_gpg_verify_data () +
+gboolean + +ostree_repo_verify_commit () +
+OstreeGpgVerifyResult * + +ostree_repo_verify_commit_ext () +
+OstreeGpgVerifyResult * + +ostree_repo_verify_commit_for_remote () +
+OstreeGpgVerifyResult * + +ostree_repo_verify_summary () +
+gboolean + +ostree_repo_regenerate_summary () +
+
+ +
+

Description

+

The OstreeRepo is like git, a content-addressed object store. +Unlike git, it records uid, gid, and extended attributes.

+

There are four possible "modes" for an OstreeRepo; OSTREE_REPO_MODE_BARE +is very simple - content files are represented exactly as they are, and +checkouts are just hardlinks. OSTREE_REPO_MODE_BARE_USER is similar, except +the uid/gids are not set on the files, and checkouts as hardlinks work only +for user checkouts. OSTREE_REPO_MODE_BARE_USER_ONLY is the same as +BARE_USER, but all metadata is not stored, so it can only be used for user +checkouts. This mode does not require xattrs. A OSTREE_REPO_MODE_ARCHIVE +(also known as OSTREE_REPO_MODE_ARCHIVE_Z2) repository in contrast stores +content files zlib-compressed. It is suitable for non-root-owned +repositories that can be served via a static HTTP server.

+

Creating an OstreeRepo does not invoke any file I/O, and thus needs +to be initialized, either from existing contents or as a new +repository. If you have an existing repo, use ostree_repo_open() +to load it from disk and check its validity. To initialize a new +repository in the given filepath, use ostree_repo_create() instead.

+

To store content in the repo, first start a transaction with +ostree_repo_prepare_transaction(). Then create a +OstreeMutableTree, and apply functions such as +ostree_repo_write_directory_to_mtree() to traverse a physical +filesystem and write content, possibly multiple times.

+

Once the OstreeMutableTree is complete, write all of its metadata +with ostree_repo_write_mtree(), and finally create a commit with +ostree_repo_write_commit().

+
+

Collection IDs

+

A collection ID is a globally unique identifier which, if set, is used to +identify refs from a repository which are mirrored elsewhere, such as in +mirror repositories or peer to peer networks.

+

This is separate from the collection-id configuration key for a remote, which +is used to store the collection ID of the repository that remote points to.

+

The collection ID should only be set on an OstreeRepo if it is the canonical +collection for some refs.

+

A collection ID must be a reverse DNS name, where the domain name is under the +control of the curator of the collection, so they can demonstrate ownership +of the collection. The later elements in the reverse DNS name can be used to +disambiguate between multiple collections from the same curator. For example, +org.exampleos.Main and org.exampleos.Apps. For the complete format of +collection IDs, see ostree_validate_collection_id().

+
+
+
+

Functions

+
+

ostree_repo_mode_from_string ()

+
gboolean
+ostree_repo_mode_from_string (const char *mode,
+                              OstreeRepoMode *out_mode,
+                              GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

mode

a repo mode as a string

 

out_mode

the corresponding OstreeRepoMode.

[out]

error

a GError if the string is not a valid mode

 
+
+
+
+
+

ostree_repo_open_at ()

+
OstreeRepo *
+ostree_repo_open_at (int dfd,
+                     const char *path,
+                     GCancellable *cancellable,
+                     GError **error);
+

This combines ostree_repo_new() (but using fd-relative access) with +ostree_repo_open(). Use this when you know you should be operating on an +already extant repository. If you want to create one, use ostree_repo_create_at().

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

dfd

Directory fd

 

path

Path

 
+
+
+

Returns

+

An accessor object for an OSTree repository located at dfd ++ path +.

+

[transfer full]

+
+

Since: 2017.10

+
+
+
+

ostree_repo_new ()

+
OstreeRepo *
+ostree_repo_new (GFile *path);
+
+

Parameters

+
+++++ + + + + + +

path

Path to a repository

 
+
+
+

Returns

+

An accessor object for an OSTree repository located at path +.

+

[transfer full]

+
+
+
+
+

ostree_repo_new_for_sysroot_path ()

+
OstreeRepo *
+ostree_repo_new_for_sysroot_path (GFile *repo_path,
+                                  GFile *sysroot_path);
+

Creates a new OstreeRepo instance, taking the system root path explicitly +instead of assuming "/".

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

repo_path

Path to a repository

 

sysroot_path

Path to the system root

 
+
+
+

Returns

+

An accessor object for the OSTree repository located at repo_path +.

+

[transfer full]

+
+
+
+
+

ostree_repo_new_default ()

+
OstreeRepo *
+ostree_repo_new_default (void);
+

If the current working directory appears to be an OSTree +repository, create a new OstreeRepo object for accessing it. +Otherwise use the path in the OSTREE_REPO environment variable +(if defined) or else the default system repository located at +/ostree/repo.

+
+

Returns

+

An accessor object for an OSTree repository located at /ostree/repo.

+

[transfer full]

+
+
+
+
+

ostree_repo_open ()

+
gboolean
+ostree_repo_open (OstreeRepo *self,
+                  GCancellable *cancellable,
+                  GError **error);
+
+
+
+

ostree_repo_set_disable_fsync ()

+
void
+ostree_repo_set_disable_fsync (OstreeRepo *self,
+                               gboolean disable_fsync);
+

Disable requests to fsync() to stable storage during commits. This +option should only be used by build system tools which are creating +disposable virtual machines, or have higher level mechanisms for +ensuring data consistency.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

An OstreeRepo

 

disable_fsync

If TRUE, do not fsync

 
+
+
+
+
+

ostree_repo_get_disable_fsync ()

+
gboolean
+ostree_repo_get_disable_fsync (OstreeRepo *self);
+

For more information see ostree_repo_set_disable_fsync().

+
+

Parameters

+
+++++ + + + + + +

self

An OstreeRepo

 
+
+
+

Returns

+

Whether or not fsync() is enabled for this repo.

+
+
+
+
+

ostree_repo_is_system ()

+
gboolean
+ostree_repo_is_system (OstreeRepo *repo);
+
+

Parameters

+
+++++ + + + + + +

repo

Repository

 
+
+
+

Returns

+

TRUE if this repository is the root-owned system global repository

+
+
+
+
+

ostree_repo_is_writable ()

+
gboolean
+ostree_repo_is_writable (OstreeRepo *self,
+                         GError **error);
+

Returns whether the repository is writable by the current user. +If the repository is not writable, the error + indicates why.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

Repo

 

error

a GError

 
+
+
+

Returns

+

TRUE if this repository is writable

+
+
+
+
+

ostree_repo_create_at ()

+
OstreeRepo *
+ostree_repo_create_at (int dfd,
+                       const char *path,
+                       OstreeRepoMode mode,
+                       GVariant *options,
+                       GCancellable *cancellable,
+                       GError **error);
+

This is a file-descriptor relative version of ostree_repo_create(). +Create the underlying structure on disk for the repository, and call +ostree_repo_open_at() on the result, preparing it for use.

+

If a repository already exists at dfd + + path + (defined by an objects/ +subdirectory existing), then this function will simply call +ostree_repo_open_at(). In other words, this function cannot be used to change +the mode or configuration (repo/config) of an existing repo.

+

The options + dict may contain:

+
  • collection-id: s: Set as collection ID in repo/config (Since 2017.9)

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

dfd

Directory fd

 

path

Path

 

mode

The mode to store the repository in

 

options

a{sv}: See below for accepted keys

 

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

A new OSTree repository reference.

+

[transfer full]

+
+

Since: 2017.10

+
+
+
+

ostree_repo_create ()

+
gboolean
+ostree_repo_create (OstreeRepo *self,
+                    OstreeRepoMode mode,
+                    GCancellable *cancellable,
+                    GError **error);
+

Create the underlying structure on disk for the repository, and call +ostree_repo_open() on the result, preparing it for use.

+

Since version 2016.8, this function will succeed on an existing +repository, and finish creating any necessary files in a partially +created repository. However, this function cannot change the mode +of an existing repository, and will silently ignore an attempt to +do so.

+

Since 2017.9, "existing repository" is defined by the existence of an +objects subdirectory.

+

This function predates ostree_repo_create_at(). It is an error to call +this function on a repository initialized via ostree_repo_open_at().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

mode

The mode to store the repository in

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_get_bootloader ()

+
const gchar *
+ostree_repo_get_bootloader (OstreeRepo *self);
+

Get the bootloader configured. See the documentation for the +"sysroot.bootloader" config key.

+
+

Parameters

+
+++++ + + + + + +

self

an OstreeRepo

 
+
+
+

Returns

+

bootloader configuration for the sysroot

+
+

Since: 2019.2

+
+
+
+

ostree_repo_get_path ()

+
GFile *
+ostree_repo_get_path (OstreeRepo *self);
+

Note that since the introduction of ostree_repo_open_at(), this function may +return a process-specific path in /proc if the repository was created using +that API. In general, you should avoid use of this API.

+
+

Parameters

+
+++++ + + + + + +

self

Repo

 
+
+
+

Returns

+

Path to repo.

+

[transfer none]

+
+
+
+
+

ostree_repo_get_mode ()

+
OstreeRepoMode
+ostree_repo_get_mode (OstreeRepo *self);
+
+
+
+

ostree_repo_get_min_free_space_bytes ()

+
gboolean
+ostree_repo_get_min_free_space_bytes (OstreeRepo *self,
+                                      guint64 *out_reserved_bytes,
+                                      GError **error);
+

Determine the number of bytes of free disk space that are reserved according +to the repo config and return that number in out_reserved_bytes +. See the +documentation for the core.min-free-space-size and +core.min-free-space-percent repo config options.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Repo

 

out_reserved_bytes

Location to store the result.

[out]

error

Return location for a GError

 
+
+
+

Returns

+

TRUE on success, FALSE otherwise.

+
+

Since: 2018.9

+
+
+
+

ostree_repo_get_config ()

+
GKeyFile *
+ostree_repo_get_config (OstreeRepo *self);
+
+

Returns

+

The repository configuration; do not modify.

+

[transfer none]

+
+
+
+
+

ostree_repo_get_dfd ()

+
int
+ostree_repo_get_dfd (OstreeRepo *self);
+

In some cases it's useful for applications to access the repository +directly; for example, writing content into repo/tmp ensures it's +on the same filesystem. Another case is detecting the mtime on the +repository (to see whether a ref was written).

+
+

Parameters

+
+++++ + + + + + +

self

Repo

 
+
+
+

Returns

+

File descriptor for repository root - owned by self +

+
+

Since: 2016.4

+
+
+
+

ostree_repo_get_default_repo_finders ()

+
const gchar * const *
+ostree_repo_get_default_repo_finders (OstreeRepo *self);
+

Get the set of default repo finders configured. See the documentation for +the "core.default-repo-finders" config key.

+
+

Parameters

+
+++++ + + + + + +

self

an OstreeRepo

 
+
+
+

Returns

+

NULL-terminated array of strings.

+

[array zero-terminated=1][element-type utf8]

+
+

Since: 2018.9

+
+
+
+

ostree_repo_hash ()

+
guint
+ostree_repo_hash (OstreeRepo *self);
+

Calculate a hash value for the given open repository, suitable for use when +putting it into a hash table. It is an error to call this on an OstreeRepo +which is not yet open, as a persistent hash value cannot be calculated until +the repository is open and the inode of its root directory has been loaded.

+

This function does no I/O.

+
+

Parameters

+
+++++ + + + + + +

self

an OstreeRepo

 
+
+
+

Returns

+

hash value for the OstreeRepo

+
+

Since: 2017.12

+
+
+
+

ostree_repo_equal ()

+
gboolean
+ostree_repo_equal (OstreeRepo *a,
+                   OstreeRepo *b);
+

Check whether two opened repositories are the same on disk: if their root +directories are the same inode. If a + or b + are not open yet (due to +ostree_repo_open() not being called on them yet), FALSE will be returned.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

a

an OstreeRepo

 

b

an OstreeRepo

 
+
+
+

Returns

+

TRUE if a +and b +are the same repository on disk, FALSE otherwise

+
+

Since: 2017.12

+
+
+
+

ostree_repo_copy_config ()

+
GKeyFile *
+ostree_repo_copy_config (OstreeRepo *self);
+
+

Returns

+

A newly-allocated copy of the repository config.

+

[transfer full]

+
+
+
+
+

ostree_repo_remote_add ()

+
gboolean
+ostree_repo_remote_add (OstreeRepo *self,
+                        const char *name,
+                        const char *url,
+                        GVariant *options,
+                        GCancellable *cancellable,
+                        GError **error);
+

Create a new remote named name + pointing to url +. If options + is +provided, then it will be mapped to GKeyFile entries, where the +GVariant dictionary key is an option string, and the value is +mapped as follows:

+
    +
  • s: g_key_file_set_string()

  • +
  • b: g_key_file_set_boolean()

  • +
  • as: g_key_file_set_string_list()

  • +
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

name

Name of remote

 

url

URL for remote (if URL begins with metalink=, it will be used as such)

 

options

GVariant of type a{sv}.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_remote_delete ()

+
gboolean
+ostree_repo_remote_delete (OstreeRepo *self,
+                           const char *name,
+                           GCancellable *cancellable,
+                           GError **error);
+

Delete the remote named name +. It is an error if the provided +remote does not exist.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

name

Name of remote

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_remote_change ()

+
gboolean
+ostree_repo_remote_change (OstreeRepo *self,
+                           GFile *sysroot,
+                           OstreeRepoRemoteChange changeop,
+                           const char *name,
+                           const char *url,
+                           GVariant *options,
+                           GCancellable *cancellable,
+                           GError **error);
+

A combined function handling the equivalent of +ostree_repo_remote_add(), ostree_repo_remote_delete(), with more +options.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

sysroot

System root.

[allow-none]

changeop

Operation to perform

 

name

Name of remote

 

url

URL for remote (if URL begins with metalink=, it will be used as such)

 

options

GVariant of type a{sv}.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_remote_list ()

+
char **
+ostree_repo_remote_list (OstreeRepo *self,
+                         guint *out_n_remotes);
+

List available remote names in an OstreeRepo. Remote names are sorted +alphabetically. If no remotes are available the function returns NULL.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

Repo

 

out_n_remotes

Number of remotes available.

[out][allow-none]
+
+
+

Returns

+

a NULL-terminated +array of remote names.

+

[array length=out_n_remotes][transfer full]

+
+
+
+
+

ostree_repo_remote_get_url ()

+
gboolean
+ostree_repo_remote_get_url (OstreeRepo *self,
+                            const char *name,
+                            char **out_url,
+                            GError **error);
+

Return the URL of the remote named name + through out_url +. It is an +error if the provided remote does not exist.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

name

Name of remote

 

out_url

Remote's URL.

[out][allow-none]

error

Error

 
+
+
+

Returns

+

TRUE on success, FALSE on failure

+
+
+
+
+

ostree_repo_remote_get_gpg_verify ()

+
gboolean
+ostree_repo_remote_get_gpg_verify (OstreeRepo *self,
+                                   const char *name,
+                                   gboolean *out_gpg_verify,
+                                   GError **error);
+

Return whether GPG verification is enabled for the remote named name + +through out_gpg_verify +. It is an error if the provided remote does +not exist.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

name

Name of remote

 

out_gpg_verify

Remote's GPG option.

[out][allow-none]

error

Error

 
+
+
+

Returns

+

TRUE on success, FALSE on failure

+
+
+
+
+

ostree_repo_remote_get_gpg_verify_summary ()

+
gboolean
+ostree_repo_remote_get_gpg_verify_summary
+                               (OstreeRepo *self,
+                                const char *name,
+                                gboolean *out_gpg_verify_summary,
+                                GError **error);
+

Return whether GPG verification of the summary is enabled for the remote +named name + through out_gpg_verify_summary +. It is an error if the provided +remote does not exist.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

name

Name of remote

 

out_gpg_verify_summary

Remote's GPG option.

[out][allow-none]

error

Error

 
+
+
+

Returns

+

TRUE on success, FALSE on failure

+
+
+
+
+

ostree_repo_remote_gpg_import ()

+
gboolean
+ostree_repo_remote_gpg_import (OstreeRepo *self,
+                               const char *name,
+                               GInputStream *source_stream,
+                               const char * const *key_ids,
+                               guint *out_imported,
+                               GCancellable *cancellable,
+                               GError **error);
+

Imports one or more GPG keys from the open source_stream +, or from the +user's personal keyring if source_stream + is NULL. The key_ids + array +can optionally restrict which keys are imported. If key_ids + is NULL, +then all keys are imported.

+

The imported keys will be used to conduct GPG verification when pulling +from the remote named name +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

name

name of a remote

 

source_stream

a GInputStream, or NULL.

[nullable]

key_ids

a NULL-terminated array of GPG key IDs, or NULL.

[array zero-terminated=1][element-type utf8][nullable]

out_imported

return location for the number of imported +keys, or NULL.

[out][optional]

cancellable

a GCancellable

 

error

a GError

 
+
+
+

Returns

+

TRUE on success, FALSE on failure

+
+
+
+
+

ostree_repo_remote_fetch_summary ()

+
gboolean
+ostree_repo_remote_fetch_summary (OstreeRepo *self,
+                                  const char *name,
+                                  GBytes **out_summary,
+                                  GBytes **out_signatures,
+                                  GCancellable *cancellable,
+                                  GError **error);
+

Tries to fetch the summary file and any GPG signatures on the summary file +over HTTP, and returns the binary data in out_summary + and out_signatures + +respectively.

+

If no summary file exists on the remote server, out_summary + is set to +NULL +. Likewise if the summary file is not signed, out_signatures + is +set to NULL +. In either case the function still returns TRUE.

+

This method does not verify the signature of the downloaded summary file. +Use ostree_repo_verify_summary() for that.

+

Parse the summary data into a GVariant using g_variant_new_from_bytes() +with OSTREE_SUMMARY_GVARIANT_FORMAT as the format string.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

name

name of a remote

 

out_summary

return location for raw summary data, or +NULL.

[out][optional]

out_signatures

return location for raw summary +signature data, or NULL.

[out][optional]

cancellable

a GCancellable

 

error

a GError

 
+
+
+

Returns

+

TRUE on success, FALSE on failure

+
+
+
+
+

ostree_repo_remote_fetch_summary_with_options ()

+
gboolean
+ostree_repo_remote_fetch_summary_with_options
+                               (OstreeRepo *self,
+                                const char *name,
+                                GVariant *options,
+                                GBytes **out_summary,
+                                GBytes **out_signatures,
+                                GCancellable *cancellable,
+                                GError **error);
+

Like ostree_repo_remote_fetch_summary(), but supports an extensible set of flags. +The following are currently defined:

+
    +
  • override-url (s): Fetch summary from this URL if remote specifies no metalink in options

  • +
  • http-headers (a(ss)): Additional headers to add to all HTTP requests

  • +
  • append-user-agent (s): Additional string to append to the user agent

  • +
  • n-network-retries (u): Number of times to retry each download on receiving +a transient network error, such as a socket timeout; default is 5, 0 +means return errors without retrying

  • +
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

name

name of a remote

 

options

A GVariant a{sv} with an extensible set of flags.

[nullable]

out_summary

return location for raw summary data, or +NULL.

[out][optional]

out_signatures

return location for raw summary +signature data, or NULL.

[out][optional]

cancellable

a GCancellable

 

error

a GError

 
+
+
+

Returns

+

TRUE on success, FALSE on failure

+
+

Since: 2016.6

+
+
+
+

ostree_repo_reload_config ()

+
gboolean
+ostree_repo_reload_config (OstreeRepo *self,
+                           GCancellable *cancellable,
+                           GError **error);
+

By default, an OstreeRepo will cache the remote configuration and its +own repo/config data. This API can be used to reload it.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

repo

 

cancellable

cancellable

 

error

error

 
+
+

Since: 2017.2

+
+
+
+

ostree_repo_get_remote_boolean_option ()

+
gboolean
+ostree_repo_get_remote_boolean_option (OstreeRepo *self,
+                                       const char *remote_name,
+                                       const char *option_name,
+                                       gboolean default_value,
+                                       gboolean *out_value,
+                                       GError **error);
+

OSTree remotes are represented by keyfile groups, formatted like: +[remote "remotename"]. This function returns a value named option_name + +underneath that group, and returns it as a boolean. +If the option is not set, out_value + will be set to default_value +. If an +error is returned, out_value + will be set to FALSE.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

A OstreeRepo

 

remote_name

Name

 

option_name

Option

 

default_value

Value returned if option_name +is not present

 

out_value

(out) : location to store the result.

 

error

Error

 
+
+
+

Returns

+

TRUE on success, otherwise FALSE with error +set

+
+

Since: 2016.5

+
+
+
+

ostree_repo_get_remote_list_option ()

+
gboolean
+ostree_repo_get_remote_list_option (OstreeRepo *self,
+                                    const char *remote_name,
+                                    const char *option_name,
+                                    char ***out_value,
+                                    GError **error);
+

OSTree remotes are represented by keyfile groups, formatted like: +[remote "remotename"]. This function returns a value named option_name + +underneath that group, and returns it as a zero terminated array of strings. +If the option is not set, or if an error is returned, out_value + will be set +to NULL.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

A OstreeRepo

 

remote_name

Name

 

option_name

Option

 

out_value

location to store the list +of strings. The list should be freed with +g_strfreev().

[out][array zero-terminated=1]

error

Error

 
+
+
+

Returns

+

TRUE on success, otherwise FALSE with error +set

+
+

Since: 2016.5

+
+
+
+

ostree_repo_get_remote_option ()

+
gboolean
+ostree_repo_get_remote_option (OstreeRepo *self,
+                               const char *remote_name,
+                               const char *option_name,
+                               const char *default_value,
+                               char **out_value,
+                               GError **error);
+

OSTree remotes are represented by keyfile groups, formatted like: +[remote "remotename"]. This function returns a value named option_name + +underneath that group, or default_value + if the remote exists but not the +option name. If an error is returned, out_value + will be set to NULL.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

A OstreeRepo

 

remote_name

Name

 

option_name

Option

 

default_value

Value returned if option_name +is not present.

[allow-none]

out_value

Return location for value.

[out]

error

Error

 
+
+
+

Returns

+

TRUE on success, otherwise FALSE with error +set

+
+

Since: 2016.5

+
+
+
+

ostree_repo_get_parent ()

+
OstreeRepo *
+ostree_repo_get_parent (OstreeRepo *self);
+

Before this function can be used, ostree_repo_init() must have been +called.

+
+

Parameters

+
+++++ + + + + + +

self

Repo

 
+
+
+

Returns

+

Parent repository, or NULL if none.

+

[transfer none]

+
+
+
+
+

ostree_repo_write_config ()

+
gboolean
+ostree_repo_write_config (OstreeRepo *self,
+                          GKeyFile *new_config,
+                          GError **error);
+

Save new_config + in place of this repository's config file.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Repo

 

new_config

Overwrite the config file with this data

 

error

a GError

 
+
+
+
+
+

ostree_repo_scan_hardlinks ()

+
gboolean
+ostree_repo_scan_hardlinks (OstreeRepo *self,
+                            GCancellable *cancellable,
+                            GError **error);
+

This function is deprecated in favor of using ostree_repo_devino_cache_new(), +which allows a precise mapping to be built up between hardlink checkout files +and their checksums between ostree_repo_checkout_at() and +ostree_repo_write_directory_to_mtree().

+

When invoking ostree_repo_write_directory_to_mtree(), it has to compute the +checksum of all files. If your commit contains hardlinks from a checkout, +this functions builds a mapping of device numbers and inodes to their +checksum.

+

There is an upfront cost to creating this mapping, as this will scan the +entire objects directory. If your commit is composed of mostly hardlinks to +existing ostree objects, then this will speed up considerably, so call it +before you call ostree_repo_write_directory_to_mtree() or similar. However, +ostree_repo_devino_cache_new() is better as it avoids scanning all objects.

+

Multithreading: This function is *not* MT safe.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_prepare_transaction ()

+
gboolean
+ostree_repo_prepare_transaction (OstreeRepo *self,
+                                 gboolean *out_transaction_resume,
+                                 GCancellable *cancellable,
+                                 GError **error);
+

Starts or resumes a transaction. In order to write to a repo, you +need to start a transaction. You can complete the transaction with +ostree_repo_commit_transaction(), or abort the transaction with +ostree_repo_abort_transaction().

+

Currently, transactions may result in partial commits or data in the target +repository if interrupted during ostree_repo_commit_transaction(), and +further writing refs is also not currently atomic.

+

There can be at most one transaction active on a repo at a time per instance +of OstreeRepo; however, it is safe to have multiple threads writing objects +on a single OstreeRepo instance as long as their lifetime is bounded by the +transaction.

+

Locking: Acquires a shared lock; release via commit or abort +Multithreading: This function is *not* MT safe; only one transaction can be +active at a time.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

out_transaction_resume

Whether this transaction +is resuming from a previous one. This is a legacy state, now OSTree +pulls use per-commit state/.commitpartial files.

[allow-none][out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_commit_transaction ()

+
gboolean
+ostree_repo_commit_transaction (OstreeRepo *self,
+                                OstreeRepoTransactionStats *out_stats,
+                                GCancellable *cancellable,
+                                GError **error);
+

Complete the transaction. Any refs set with +ostree_repo_transaction_set_ref() or +ostree_repo_transaction_set_refspec() will be written out.

+

Note that if multiple threads are performing writes, all such threads must +have terminated before this function is invoked.

+

Locking: Releases shared lock acquired by ostree_repo_prepare_transaction() +Multithreading: This function is *not* MT safe; only one transaction can be +active at a time.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

out_stats

A set of statistics of things +that happened during this transaction.

[allow-none][out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_abort_transaction ()

+
gboolean
+ostree_repo_abort_transaction (OstreeRepo *self,
+                               GCancellable *cancellable,
+                               GError **error);
+

Abort the active transaction; any staged objects and ref changes will be +discarded. You *must* invoke this if you have chosen not to invoke +ostree_repo_commit_transaction(). Calling this function when not in a +transaction will do nothing and return successfully.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_transaction_set_refspec ()

+
void
+ostree_repo_transaction_set_refspec (OstreeRepo *self,
+                                     const char *refspec,
+                                     const char *checksum);
+

Like ostree_repo_transaction_set_ref(), but takes concatenated +refspec + format as input instead of separate remote and name +arguments.

+

Multithreading: Since v2017.15 this function is MT safe.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

refspec

The refspec to write

 

checksum

The checksum to point it to.

[nullable]
+
+
+
+
+

ostree_repo_transaction_set_ref ()

+
void
+ostree_repo_transaction_set_ref (OstreeRepo *self,
+                                 const char *remote,
+                                 const char *ref,
+                                 const char *checksum);
+

If checksum + is not NULL, then record it as the target of ref named +ref +; if remote + is provided, the ref will appear to originate from that +remote.

+

Otherwise, if checksum + is NULL, then record that the ref should +be deleted.

+

The change will be written when the transaction is completed with +ostree_repo_commit_transaction(); that function takes care of writing all of +the objects (such as the commit referred to by checksum +) before updating the +refs. If the transaction is instead aborted with +ostree_repo_abort_transaction(), no changes to the ref will be made to the +repository.

+

Note however that currently writing *multiple* refs is not truly atomic; if +the process or system is terminated during +ostree_repo_commit_transaction(), it is possible that just some of the refs +will have been updated. Your application should take care to handle this +case.

+

Multithreading: Since v2017.15 this function is MT safe.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

remote

A remote for the ref.

[allow-none]

ref

The ref to write

 

checksum

The checksum to point it to.

[nullable]
+
+
+
+
+

ostree_repo_set_ref_immediate ()

+
gboolean
+ostree_repo_set_ref_immediate (OstreeRepo *self,
+                               const char *remote,
+                               const char *ref,
+                               const char *checksum,
+                               GCancellable *cancellable,
+                               GError **error);
+

This is like ostree_repo_transaction_set_ref(), except it may be +invoked outside of a transaction. This is presently safe for the +case where we're creating or overwriting an existing ref.

+

Multithreading: This function is MT safe.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

remote

A remote for the ref.

[allow-none]

ref

The ref to write

 

checksum

The checksum to point it to, or NULL to unset.

[allow-none]

cancellable

GCancellable

 

error

GError

 
+
+
+
+
+

ostree_repo_set_alias_ref_immediate ()

+
gboolean
+ostree_repo_set_alias_ref_immediate (OstreeRepo *self,
+                                     const char *remote,
+                                     const char *ref,
+                                     const char *target,
+                                     GCancellable *cancellable,
+                                     GError **error);
+

Like ostree_repo_set_ref_immediate(), but creates an alias.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

remote

A remote for the ref.

[allow-none]

ref

The ref to write

 

target

The ref target to point it to, or NULL to unset.

[allow-none]

cancellable

GCancellable

 

error

GError

 
+
+

Since: 2017.10

+
+
+
+

ostree_repo_set_cache_dir ()

+
gboolean
+ostree_repo_set_cache_dir (OstreeRepo *self,
+                           int dfd,
+                           const char *path,
+                           GCancellable *cancellable,
+                           GError **error);
+

Set a custom location for the cache directory used for e.g. +per-remote summary caches. Setting this manually is useful when +doing operations on a system repo as a user because you don't have +write permissions in the repo, where the cache is normally stored.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

dfd

directory fd

 

path

subpath in dfd +

 

cancellable

a GCancellable

 

error

a GError

 
+
+

Since: 2016.5

+
+
+
+

ostree_repo_sign_delta ()

+
gboolean
+ostree_repo_sign_delta (OstreeRepo *self,
+                        const gchar *from_commit,
+                        const gchar *to_commit,
+                        const gchar *key_id,
+                        const gchar *homedir,
+                        GCancellable *cancellable,
+                        GError **error);
+

This function is deprecated, sign the summary file instead. +Add a GPG signature to a static delta.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

from_commit

From commit

 

to_commit

To commit

 

key_id

key id

 

homedir

homedir

 

cancellable

cancellable

 

error

error

 
+
+
+
+
+

ostree_repo_has_object ()

+
gboolean
+ostree_repo_has_object (OstreeRepo *self,
+                        OstreeObjectType objtype,
+                        const char *checksum,
+                        gboolean *out_have_object,
+                        GCancellable *cancellable,
+                        GError **error);
+

Set out_have_object + to TRUE if self + contains the given object; +FALSE otherwise.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

checksum

ASCII SHA256 checksum

 

out_have_object

TRUE if repository contains object.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

FALSE if an unexpected error occurred, TRUE otherwise

+
+
+
+
+

ostree_repo_mark_commit_partial ()

+
gboolean
+ostree_repo_mark_commit_partial (OstreeRepo *self,
+                                 const char *checksum,
+                                 gboolean is_partial,
+                                 GError **error);
+

Commits in the "partial" state do not have all their child objects +written. This occurs in various situations, such as during a pull, +but also if a "subpath" pull is used, as well as "commit only" +pulls.

+

This function is used by ostree_repo_pull_with_options(); you +should use this if you are implementing a different type of transport.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

checksum

Commit SHA-256

 

is_partial

Whether or not this commit is partial

 

error

Error

 
+
+

Since: 2017.15

+
+
+
+

ostree_repo_mark_commit_partial_reason ()

+
gboolean
+ostree_repo_mark_commit_partial_reason
+                               (OstreeRepo *self,
+                                const char *checksum,
+                                gboolean is_partial,
+                                OstreeRepoCommitState in_state,
+                                GError **error);
+

Allows the setting of a reason code for a partial commit. Presently +it only supports setting reason bitmask to +OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL, or +OSTREE_REPO_COMMIT_STATE_NORMAL. This will allow successive ostree +fsck operations to exit properly with an error code if the +repository has been truncated as a result of fsck trying to repair +it.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

checksum

Commit SHA-256

 

is_partial

Whether or not this commit is partial

 

in_state

Reason bitmask for partial commit

 

error

Error

 
+
+

Since: 2019.4

+
+
+
+

ostree_repo_write_metadata ()

+
gboolean
+ostree_repo_write_metadata (OstreeRepo *self,
+                            OstreeObjectType objtype,
+                            const char *expected_checksum,
+                            GVariant *object,
+                            guchar **out_csum,
+                            GCancellable *cancellable,
+                            GError **error);
+

Store the metadata object object +. Return the checksum +as out_csum +.

+

If expected_checksum + is not NULL, verify it against the +computed checksum.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

expected_checksum

If provided, validate content against this checksum.

[allow-none]

object

Metadata

 

out_csum

Binary checksum.

[out][array fixed-size=32][allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_metadata_async ()

+
void
+ostree_repo_write_metadata_async (OstreeRepo *self,
+                                  OstreeObjectType objtype,
+                                  const char *expected_checksum,
+                                  GVariant *object,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data);
+

Asynchronously store the metadata object variant +. If provided, +the checksum expected_checksum + will be verified.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

expected_checksum

If provided, validate content against this checksum.

[allow-none]

object

Metadata

 

cancellable

Cancellable

 

callback

Invoked when metadata is writed

 

user_data

Data for callback +

 
+
+
+
+
+

ostree_repo_write_metadata_finish ()

+
gboolean
+ostree_repo_write_metadata_finish (OstreeRepo *self,
+                                   GAsyncResult *result,
+                                   guchar **out_csum,
+                                   GError **error);
+

Complete a call to ostree_repo_write_metadata_async().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

result

Result

 

out_csum

Binary checksum value.

[out][array fixed-size=32][element-type guint8]

error

Error

 
+
+
+
+
+

ostree_repo_write_content ()

+
gboolean
+ostree_repo_write_content (OstreeRepo *self,
+                           const char *expected_checksum,
+                           GInputStream *object_input,
+                           guint64 length,
+                           guchar **out_csum,
+                           GCancellable *cancellable,
+                           GError **error);
+

Store the content object streamed as object_input +, +with total length length +. The actual checksum will +be returned as out_csum +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

expected_checksum

If provided, validate content against this checksum.

[allow-none]

object_input

Content object stream

 

length

Length of object_input +

 

out_csum

Binary checksum.

[out][array fixed-size=32][allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_metadata_trusted ()

+
gboolean
+ostree_repo_write_metadata_trusted (OstreeRepo *self,
+                                    OstreeObjectType objtype,
+                                    const char *checksum,
+                                    GVariant *variant,
+                                    GCancellable *cancellable,
+                                    GError **error);
+

Store the metadata object variant +; the provided checksum + is +trusted.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

checksum

Store object with this ASCII SHA256 checksum

 

variant

Metadata object

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_metadata_stream_trusted ()

+
gboolean
+ostree_repo_write_metadata_stream_trusted
+                               (OstreeRepo *self,
+                                OstreeObjectType objtype,
+                                const char *checksum,
+                                GInputStream *object_input,
+                                guint64 length,
+                                GCancellable *cancellable,
+                                GError **error);
+

Store the metadata object variant +; the provided checksum + is +trusted.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

checksum

Store object with this ASCII SHA256 checksum

 

object_input

Metadata object stream

 

length

Length, may be 0 for unknown

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_content_trusted ()

+
gboolean
+ostree_repo_write_content_trusted (OstreeRepo *self,
+                                   const char *checksum,
+                                   GInputStream *object_input,
+                                   guint64 length,
+                                   GCancellable *cancellable,
+                                   GError **error);
+

Store the content object streamed as object_input +, with total +length length +. The given checksum + will be treated as trusted.

+

This function should be used when importing file objects from local +disk, for example.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

checksum

Store content using this ASCII SHA256 checksum

 

object_input

Content stream

 

length

Length of object_input +

 

cancellable

Cancellable

 

error

Data for callback +

 
+
+
+
+
+

ostree_repo_write_content_async ()

+
void
+ostree_repo_write_content_async (OstreeRepo *self,
+                                 const char *expected_checksum,
+                                 GInputStream *object,
+                                 guint64 length,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data);
+

Asynchronously store the content object object +. If provided, the +checksum expected_checksum + will be verified.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

expected_checksum

If provided, validate content against this checksum.

[allow-none]

object

Input

 

length

Length of object +

 

cancellable

Cancellable

 

callback

Invoked when content is writed

 

user_data

User data for callback +

 
+
+
+
+
+

ostree_repo_write_content_finish ()

+
gboolean
+ostree_repo_write_content_finish (OstreeRepo *self,
+                                  GAsyncResult *result,
+                                  guchar **out_csum,
+                                  GError **error);
+

Completes an invocation of ostree_repo_write_content_async().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

a OstreeRepo

 

result

a GAsyncResult

 

out_csum

A binary SHA256 checksum of the content object.

[out][transfer full]

error

a GError

 
+
+
+
+
+

ostree_repo_resolve_rev ()

+
gboolean
+ostree_repo_resolve_rev (OstreeRepo *self,
+                         const char *refspec,
+                         gboolean allow_noent,
+                         char **out_rev,
+                         GError **error);
+

Look up the given refspec, returning the checksum it references in +the parameter out_rev +. Will fall back on remote directory if cannot +find the given refspec in local.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

refspec

A refspec

 

allow_noent

Do not throw an error if refspec does not exist

 

out_rev

A checksum,or NULL if allow_noent +is true and it does not exist.

[out][transfer full]

error

Error

 
+
+
+
+
+

ostree_repo_resolve_rev_ext ()

+
gboolean
+ostree_repo_resolve_rev_ext (OstreeRepo *self,
+                             const char *refspec,
+                             gboolean allow_noent,
+                             OstreeRepoResolveRevExtFlags flags,
+                             char **out_rev,
+                             GError **error);
+

Look up the given refspec, returning the checksum it references in +the parameter out_rev +. Differently from ostree_repo_resolve_rev(), +this will not fall back to searching through remote repos if a +local ref is specified but not found.

+

The flag OSTREE_REPO_RESOLVE_REV_EXT_LOCAL_ONLY is implied so +using it has no effect.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

refspec

A refspec

 

allow_noent

Do not throw an error if refspec does not exist

 

flags

Options controlling behavior

 

out_rev

A checksum,or NULL if allow_noent +is true and it does not exist.

[out][transfer full]

error

Error

 
+
+

Since: 2016.7

+
+
+
+

ostree_repo_list_refs ()

+
gboolean
+ostree_repo_list_refs (OstreeRepo *self,
+                       const char *refspec_prefix,
+                       GHashTable **out_all_refs,
+                       GCancellable *cancellable,
+                       GError **error);
+

If refspec_prefix + is NULL, list all local and remote refspecs, +with their current values in out_all_refs +. Otherwise, only list +refspecs which have refspec_prefix + as a prefix.

+

out_all_refs + will be returned as a mapping from refspecs (including the +remote name) to checksums. If refspec_prefix + is non-NULL, it will be +removed as a prefix from the hash table keys.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

refspec_prefix

Only list refs which match this prefix.

[allow-none]

out_all_refs

Mapping from refspec to checksum.

[out][element-type utf8 utf8][transfer container]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_list_refs_ext ()

+
gboolean
+ostree_repo_list_refs_ext (OstreeRepo *self,
+                           const char *refspec_prefix,
+                           GHashTable **out_all_refs,
+                           OstreeRepoListRefsExtFlags flags,
+                           GCancellable *cancellable,
+                           GError **error);
+

If refspec_prefix + is NULL, list all local and remote refspecs, +with their current values in out_all_refs +. Otherwise, only list +refspecs which have refspec_prefix + as a prefix.

+

out_all_refs + will be returned as a mapping from refspecs (including the +remote name) to checksums. Differently from ostree_repo_list_refs(), the +refspec_prefix + will not be removed from the refspecs in the hash table.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

refspec_prefix

Only list refs which match this prefix.

[allow-none]

out_all_refs

Mapping from refspec to checksum.

[out][element-type utf8 utf8][transfer container]

flags

Options controlling listing behavior

 

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2016.4

+
+
+
+

ostree_repo_remote_list_refs ()

+
gboolean
+ostree_repo_remote_list_refs (OstreeRepo *self,
+                              const char *remote_name,
+                              GHashTable **out_all_refs,
+                              GCancellable *cancellable,
+                              GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

remote_name

Name of the remote.

 

out_all_refs

Mapping from ref to checksum.

[out][element-type utf8 utf8][transfer container]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_load_variant ()

+
gboolean
+ostree_repo_load_variant (OstreeRepo *self,
+                          OstreeObjectType objtype,
+                          const char *sha256,
+                          GVariant **out_variant,
+                          GError **error);
+

Load the metadata object sha256 + of type objtype +, storing the +result in out_variant +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Expected object type

 

sha256

Checksum string

 

out_variant

Metadata object.

[out][transfer full]

error

Error

 
+
+
+
+
+

ostree_repo_load_commit ()

+
gboolean
+ostree_repo_load_commit (OstreeRepo *self,
+                         const char *checksum,
+                         GVariant **out_commit,
+                         OstreeRepoCommitState *out_state,
+                         GError **error);
+

A version of ostree_repo_load_variant() specialized to commits, +capable of returning extended state information. Currently +the only extended state is OSTREE_REPO_COMMIT_STATE_PARTIAL, which +means that only a sub-path of the commit is available.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

checksum

Commit checksum

 

out_commit

Commit.

[out][allow-none]

out_state

Commit state.

[out][allow-none]

error

Error

 
+
+
+
+
+

ostree_repo_load_variant_if_exists ()

+
gboolean
+ostree_repo_load_variant_if_exists (OstreeRepo *self,
+                                    OstreeObjectType objtype,
+                                    const char *sha256,
+                                    GVariant **out_variant,
+                                    GError **error);
+

Attempt to load the metadata object sha256 + of type objtype + if it +exists, storing the result in out_variant +. If it doesn't exist, +NULL is returned.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

sha256

ASCII checksum

 

out_variant

Metadata.

[out][transfer full]

error

Error

 
+
+
+
+
+

ostree_repo_load_file ()

+
gboolean
+ostree_repo_load_file (OstreeRepo *self,
+                       const char *checksum,
+                       GInputStream **out_input,
+                       GFileInfo **out_file_info,
+                       GVariant **out_xattrs,
+                       GCancellable *cancellable,
+                       GError **error);
+

Load content object, decomposing it into three parts: the actual +content (for regular files), the metadata, and extended attributes.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

checksum

ASCII SHA256 checksum

 

out_input

File content.

[out][optional][nullable]

out_file_info

File information.

[out][optional][nullable]

out_xattrs

Extended attributes.

[out][optional][nullable]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_load_object_stream ()

+
gboolean
+ostree_repo_load_object_stream (OstreeRepo *self,
+                                OstreeObjectType objtype,
+                                const char *checksum,
+                                GInputStream **out_input,
+                                guint64 *out_size,
+                                GCancellable *cancellable,
+                                GError **error);
+

Load object as a stream; useful when copying objects between +repositories.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

checksum

ASCII SHA256 checksum

 

out_input

Stream for object.

[out]

out_size

Length of out_input +.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_query_object_storage_size ()

+
gboolean
+ostree_repo_query_object_storage_size (OstreeRepo *self,
+                                       OstreeObjectType objtype,
+                                       const char *sha256,
+                                       guint64 *out_size,
+                                       GCancellable *cancellable,
+                                       GError **error);
+

Return the size in bytes of object with checksum sha256 +, after any +compression has been applied.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

sha256

Checksum

 

out_size

Size in bytes object occupies physically.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_import_object_from ()

+
gboolean
+ostree_repo_import_object_from (OstreeRepo *self,
+                                OstreeRepo *source,
+                                OstreeObjectType objtype,
+                                const char *checksum,
+                                GCancellable *cancellable,
+                                GError **error);
+

Copy object named by objtype + and checksum + into self + from the +source repository source +. If both repositories are of the same +type and on the same filesystem, this will simply be a fast Unix +hard link operation.

+

Otherwise, a copy will be performed.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Destination repo

 

source

Source repo

 

objtype

Object type

 

checksum

checksum

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_import_object_from_with_trust ()

+
gboolean
+ostree_repo_import_object_from_with_trust
+                               (OstreeRepo *self,
+                                OstreeRepo *source,
+                                OstreeObjectType objtype,
+                                const char *checksum,
+                                gboolean trusted,
+                                GCancellable *cancellable,
+                                GError **error);
+

Copy object named by objtype + and checksum + into self + from the +source repository source +. If trusted + is TRUE and both +repositories are of the same type and on the same filesystem, +this will simply be a fast Unix hard link operation.

+

Otherwise, a copy will be performed.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Destination repo

 

source

Source repo

 

objtype

Object type

 

checksum

checksum

 

trusted

If TRUE, assume the source repo is valid and trusted

 

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2016.5

+
+
+
+

ostree_repo_import_archive_to_mtree ()

+
gboolean
+ostree_repo_import_archive_to_mtree (OstreeRepo *self,
+                                     OstreeRepoImportArchiveOptions *opts,
+                                     void *archive,
+                                     OstreeMutableTree *mtree,
+                                     OstreeRepoCommitModifier *modifier,
+                                     GCancellable *cancellable,
+                                     GError **error);
+

Import an archive file archive + into the repository, and write its +file structure to mtree +.

+

[skip]

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

opts

Options structure, ensure this is zeroed, then set specific variables

 

archive

Really this is "struct archive*"

 

mtree

The OstreeMutableTree to write to

 

modifier

Optional commit modifier.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_export_tree_to_archive ()

+
gboolean
+ostree_repo_export_tree_to_archive (OstreeRepo *self,
+                                    OstreeRepoExportArchiveOptions *opts,
+                                    OstreeRepoFile *root,
+                                    void *archive,
+                                    GCancellable *cancellable,
+                                    GError **error);
+

Import an archive file archive + into the repository, and write its +file structure to mtree +.

+

[skip]

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

opts

Options controlling conversion

 

root

An OstreeRepoFile for the base directory

 

archive

A struct archive, but specified as void to avoid a dependency on the libarchive headers

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_delete_object ()

+
gboolean
+ostree_repo_delete_object (OstreeRepo *self,
+                           OstreeObjectType objtype,
+                           const char *sha256,
+                           GCancellable *cancellable,
+                           GError **error);
+

Remove the object of type objtype + with checksum sha256 + +from the repository. An error of type G_IO_ERROR_NOT_FOUND +is thrown if the object does not exist.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

sha256

Checksum

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_fsck_object ()

+
gboolean
+ostree_repo_fsck_object (OstreeRepo *self,
+                         OstreeObjectType objtype,
+                         const char *sha256,
+                         GCancellable *cancellable,
+                         GError **error);
+

Verify consistency of the object; this performs checks only relevant to the +immediate object itself, such as checksumming. This API call will not itself +traverse metadata objects for example.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

objtype

Object type

 

sha256

Checksum

 

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2017.15

+
+
+
+

OstreeRepoCommitFilter ()

+
OstreeRepoCommitFilterResult
+(*OstreeRepoCommitFilter) (OstreeRepo *repo,
+                           const char *path,
+                           GFileInfo *file_info,
+                           gpointer user_data);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

repo

Repo

 

path

Path to file

 

file_info

File information

 

user_data

User data

 
+
+
+

Returns

+

OstreeRepoCommitFilterResult saying whether or not to commit this file

+
+
+
+
+

ostree_repo_commit_modifier_new ()

+
OstreeRepoCommitModifier *
+ostree_repo_commit_modifier_new (OstreeRepoCommitModifierFlags flags,
+                                 OstreeRepoCommitFilter commit_filter,
+                                 gpointer user_data,
+                                 GDestroyNotify destroy_notify);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

flags

Control options for filter

 

commit_filter

Function that can inspect individual files.

[allow-none]

user_data

User data.

[allow-none]

destroy_notify

A GDestroyNotify

 
+
+
+

Returns

+

A new commit modifier.

+

[transfer full]

+
+
+
+
+

OstreeRepoCommitModifierXattrCallback ()

+
GVariant *
+(*OstreeRepoCommitModifierXattrCallback)
+                               (OstreeRepo *repo,
+                                const char *path,
+                                GFileInfo *file_info,
+                                gpointer user_data);
+
+
+
+

ostree_repo_commit_modifier_set_xattr_callback ()

+
void
+ostree_repo_commit_modifier_set_xattr_callback
+                               (OstreeRepoCommitModifier *modifier,
+                                OstreeRepoCommitModifierXattrCallback callback,
+                                GDestroyNotify destroy,
+                                gpointer user_data);
+

If set, this function should return extended attributes to use for +the given path. This is useful for things like ACLs and SELinux, +where a build system can label the files as it's committing to the +repository.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

modifier

An OstreeRepoCommitModifier

 

callback

Function to be invoked, should return extended attributes for path

 

destroy

Destroy notification

 

user_data

Data for callback +:

 
+
+
+
+
+

ostree_repo_commit_modifier_set_sepolicy ()

+
void
+ostree_repo_commit_modifier_set_sepolicy
+                               (OstreeRepoCommitModifier *modifier,
+                                OstreeSePolicy *sepolicy);
+

If policy + is non-NULL, use it to look up labels to use for +"security.selinux" extended attributes.

+

Note that any policy specified this way operates in addition to any +extended attributes provided via +ostree_repo_commit_modifier_set_xattr_callback(). However if both +specify a value for "security.selinux", then the one from the +policy wins.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

modifier

An OstreeRepoCommitModifier

 

sepolicy

Policy to use for labeling.

[allow-none]
+
+
+
+
+

ostree_repo_commit_modifier_set_sepolicy_from_commit ()

+
gboolean
+ostree_repo_commit_modifier_set_sepolicy_from_commit
+                               (OstreeRepoCommitModifier *modifier,
+                                OstreeRepo *repo,
+                                const char *rev,
+                                GCancellable *cancellable,
+                                GError **error);
+

In many cases, one wants to create a "derived" commit from base commit. +SELinux policy labels are part of that base commit. This API allows +one to easily set up SELinux labeling from a base commit.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

modifier

Commit modifier

 

repo

OSTree repo containing rev +

 

rev

Find SELinux policy from this base commit

 
+
+
+
+
+

ostree_repo_commit_modifier_set_devino_cache ()

+
void
+ostree_repo_commit_modifier_set_devino_cache
+                               (OstreeRepoCommitModifier *modifier,
+                                OstreeRepoDevInoCache *cache);
+

See the documentation for +ostree_repo_devino_cache_new(). This function can +then be used for later calls to +ostree_repo_write_directory_to_mtree() to optimize commits.

+

Note if your process has multiple writers, you should use separate +OSTreeRepo instances if you want to also use this API.

+

This function will add a reference to cache + without copying - you +should avoid further mutation of the cache.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

modifier

Modifier

 

cache

A hash table caching device,inode to checksums

 
+
+

Since: 2017.13

+
+
+
+

ostree_repo_commit_modifier_ref ()

+
OstreeRepoCommitModifier *
+ostree_repo_commit_modifier_ref (OstreeRepoCommitModifier *modifier);
+
+
+
+

ostree_repo_commit_modifier_unref ()

+
void
+ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier);
+
+
+
+

ostree_repo_devino_cache_new ()

+
OstreeRepoDevInoCache *
+ostree_repo_devino_cache_new (void);
+

OSTree has support for pairing ostree_repo_checkout_tree_at() using +hardlinks in combination with a later +ostree_repo_write_directory_to_mtree() using a (normally modified) +directory. In order for OSTree to optimally detect just the new +files, use this function and fill in the devino_to_csum_cache +member of OstreeRepoCheckoutAtOptions, then call +ostree_repo_commit_set_devino_cache().

+
+

Returns

+

Newly allocated cache.

+

[transfer full]

+
+
+
+
+

ostree_repo_devino_cache_ref ()

+
OstreeRepoDevInoCache *
+ostree_repo_devino_cache_ref (OstreeRepoDevInoCache *cache);
+
+
+
+

ostree_repo_devino_cache_unref ()

+
void
+ostree_repo_devino_cache_unref (OstreeRepoDevInoCache *cache);
+
+
+
+

ostree_repo_devino_cache_get_type ()

+
GType
+ostree_repo_devino_cache_get_type (void);
+
+
+
+

ostree_repo_write_directory_to_mtree ()

+
gboolean
+ostree_repo_write_directory_to_mtree (OstreeRepo *self,
+                                      GFile *dir,
+                                      OstreeMutableTree *mtree,
+                                      OstreeRepoCommitModifier *modifier,
+                                      GCancellable *cancellable,
+                                      GError **error);
+

Store objects for dir + and all children into the repository self +, +overlaying the resulting filesystem hierarchy into mtree +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

dir

Path to a directory

 

mtree

Overlay directory contents into this tree

 

modifier

Optional modifier.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_dfd_to_mtree ()

+
gboolean
+ostree_repo_write_dfd_to_mtree (OstreeRepo *self,
+                                int dfd,
+                                const char *path,
+                                OstreeMutableTree *mtree,
+                                OstreeRepoCommitModifier *modifier,
+                                GCancellable *cancellable,
+                                GError **error);
+

Store as objects all contents of the directory referred to by dfd + +and path + all children into the repository self +, overlaying the +resulting filesystem hierarchy into mtree +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

dfd

Directory file descriptor

 

path

Path

 

mtree

Overlay directory contents into this tree

 

modifier

Optional modifier.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_archive_to_mtree ()

+
gboolean
+ostree_repo_write_archive_to_mtree (OstreeRepo *self,
+                                    GFile *archive,
+                                    OstreeMutableTree *mtree,
+                                    OstreeRepoCommitModifier *modifier,
+                                    gboolean autocreate_parents,
+                                    GCancellable *cancellable,
+                                    GError **error);
+

Import an archive file archive + into the repository, and write its +file structure to mtree +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

archive

A path to an archive file

 

mtree

The OstreeMutableTree to write to

 

modifier

Optional commit modifier.

[allow-none]

autocreate_parents

Autocreate parent directories

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_archive_to_mtree_from_fd ()

+
gboolean
+ostree_repo_write_archive_to_mtree_from_fd
+                               (OstreeRepo *self,
+                                int fd,
+                                OstreeMutableTree *mtree,
+                                OstreeRepoCommitModifier *modifier,
+                                gboolean autocreate_parents,
+                                GCancellable *cancellable,
+                                GError **error);
+

Read an archive from fd + and import it into the repository, writing +its file structure to mtree +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

An OstreeRepo

 

fd

A file descriptor to read the archive from

 

mtree

The OstreeMutableTree to write to

 

modifier

Optional commit modifier.

[allow-none]

autocreate_parents

Autocreate parent directories

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_mtree ()

+
gboolean
+ostree_repo_write_mtree (OstreeRepo *self,
+                         OstreeMutableTree *mtree,
+                         GFile **out_file,
+                         GCancellable *cancellable,
+                         GError **error);
+

Write all metadata objects for mtree + to repo; the resulting +out_file + points to the OSTREE_OBJECT_TYPE_DIR_TREE object that +the mtree + represented.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

mtree

Mutable tree

 

out_file

An OstreeRepoFile representing mtree +'s root.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_commit ()

+
gboolean
+ostree_repo_write_commit (OstreeRepo *self,
+                          const char *parent,
+                          const char *subject,
+                          const char *body,
+                          GVariant *metadata,
+                          OstreeRepoFile *root,
+                          char **out_commit,
+                          GCancellable *cancellable,
+                          GError **error);
+

Write a commit metadata object, referencing root_contents_checksum + +and root_metadata_checksum +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

parent

ASCII SHA256 checksum for parent, or NULL for none.

[allow-none]

subject

Subject.

[allow-none]

body

Body.

[allow-none]

metadata

GVariant of type a{sv}, or NULL for none.

[allow-none]

root

The tree to point the commit to

 

out_commit

Resulting ASCII SHA256 checksum for commit.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_commit_with_time ()

+
gboolean
+ostree_repo_write_commit_with_time (OstreeRepo *self,
+                                    const char *parent,
+                                    const char *subject,
+                                    const char *body,
+                                    GVariant *metadata,
+                                    OstreeRepoFile *root,
+                                    guint64 time,
+                                    char **out_commit,
+                                    GCancellable *cancellable,
+                                    GError **error);
+

Write a commit metadata object, referencing root_contents_checksum + +and root_metadata_checksum +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

parent

ASCII SHA256 checksum for parent, or NULL for none.

[allow-none]

subject

Subject.

[allow-none]

body

Body.

[allow-none]

metadata

GVariant of type a{sv}, or NULL for none.

[allow-none]

root

The tree to point the commit to

 

time

The time to use to stamp the commit

 

out_commit

Resulting ASCII SHA256 checksum for commit.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_read_commit_detached_metadata ()

+
gboolean
+ostree_repo_read_commit_detached_metadata
+                               (OstreeRepo *self,
+                                const char *checksum,
+                                GVariant **out_metadata,
+                                GCancellable *cancellable,
+                                GError **error);
+

OSTree commits can have arbitrary metadata associated; this +function retrieves them. If none exists, out_metadata + will be set +to NULL.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

checksum

ASCII SHA256 commit checksum

 

out_metadata

Metadata associated with commit in with format "a{sv}", or NULL if none exists.

[out][transfer full]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_write_commit_detached_metadata ()

+
gboolean
+ostree_repo_write_commit_detached_metadata
+                               (OstreeRepo *self,
+                                const char *checksum,
+                                GVariant *metadata,
+                                GCancellable *cancellable,
+                                GError **error);
+

Replace any existing metadata associated with commit referred to by +checksum + with metadata +. If metadata + is NULL, then existing +data will be deleted.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

checksum

ASCII SHA256 commit checksum

 

metadata

Metadata to associate with commit in with format "a{sv}", or NULL to delete.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_checkout_at_options_set_devino ()

+
void
+ostree_repo_checkout_at_options_set_devino
+                               (OstreeRepoCheckoutAtOptions *opts,
+                                OstreeRepoDevInoCache *cache);
+

This function simply assigns cache + to the devino_to_csum_cache member of +opts +; it's only useful for introspection.

+

Note that cache does *not* have its refcount incremented - the lifetime of +cache + must be equal to or greater than that of opts +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

opts

Checkout options

 

cache

Devino cache.

[transfer none][nullable]
+
+

Since: 2017.13

+
+
+
+

ostree_repo_checkout_tree ()

+
gboolean
+ostree_repo_checkout_tree (OstreeRepo *self,
+                           OstreeRepoCheckoutMode mode,
+                           OstreeRepoCheckoutOverwriteMode overwrite_mode,
+                           GFile *destination,
+                           OstreeRepoFile *source,
+                           GFileInfo *source_info,
+                           GCancellable *cancellable,
+                           GError **error);
+

Check out source + into destination +, which must live on the +physical filesystem. source + may be any subdirectory of a given +commit. The mode + and overwrite_mode + allow control over how the +files are checked out.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

mode

Options controlling all files

 

overwrite_mode

Whether or not to overwrite files

 

destination

Place tree here

 

source

Source tree

 

source_info

Source info

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_checkout_tree_at ()

+
gboolean
+ostree_repo_checkout_tree_at (OstreeRepo *self,
+                              OstreeRepoCheckoutOptions *options,
+                              int destination_dfd,
+                              const char *destination_path,
+                              const char *commit,
+                              GCancellable *cancellable,
+                              GError **error);
+

ostree_repo_checkout_tree_at is deprecated and should not be used in newly-written code.

+

Similar to ostree_repo_checkout_tree(), but uses directory-relative +paths for the destination, uses a new OstreeRepoCheckoutAtOptions, +and takes a commit checksum and optional subpath pair, rather than +requiring use of GFile APIs for the caller.

+

Note in addition that unlike ostree_repo_checkout_tree(), the +default is not to use the repository-internal uncompressed objects +cache.

+

This function is deprecated. Use ostree_repo_checkout_at() instead.

+

[skip]

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

options

Options.

[allow-none]

destination_dfd

Directory FD for destination

 

destination_path

Directory for destination

 

commit

Checksum for commit

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_checkout_at ()

+
gboolean
+ostree_repo_checkout_at (OstreeRepo *self,
+                         OstreeRepoCheckoutAtOptions *options,
+                         int destination_dfd,
+                         const char *destination_path,
+                         const char *commit,
+                         GCancellable *cancellable,
+                         GError **error);
+

Similar to ostree_repo_checkout_tree(), but uses directory-relative +paths for the destination, uses a new OstreeRepoCheckoutAtOptions, +and takes a commit checksum and optional subpath pair, rather than +requiring use of GFile APIs for the caller.

+

It also replaces ostree_repo_checkout_at() which was not safe to +use with GObject introspection.

+

Note in addition that unlike ostree_repo_checkout_tree(), the +default is not to use the repository-internal uncompressed objects +cache.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

options

Options.

[allow-none]

destination_dfd

Directory FD for destination

 

destination_path

Directory for destination

 

commit

Checksum for commit

 

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2016.8

+
+
+
+

ostree_repo_checkout_gc ()

+
gboolean
+ostree_repo_checkout_gc (OstreeRepo *self,
+                         GCancellable *cancellable,
+                         GError **error);
+

Call this after finishing a succession of checkout operations; it +will delete any currently-unused uncompressed objects from the +cache.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Repo

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_read_commit ()

+
gboolean
+ostree_repo_read_commit (OstreeRepo *self,
+                         const char *ref,
+                         GFile **out_root,
+                         char **out_commit,
+                         GCancellable *cancellable,
+                         GError **error);
+

Load the content for rev + into out_root +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

ref

Ref or ASCII checksum

 

out_root

An OstreeRepoFile corresponding to the root.

[out]

out_commit

The resolved commit checksum.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_list_objects ()

+
gboolean
+ostree_repo_list_objects (OstreeRepo *self,
+                          OstreeRepoListObjectsFlags flags,
+                          GHashTable **out_objects,
+                          GCancellable *cancellable,
+                          GError **error);
+

This function synchronously enumerates all objects in the +repository, returning data in out_objects +. out_objects + +maps from keys returned by ostree_object_name_serialize() +to GVariant values of type OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

flags

Flags controlling enumeration

 

out_objects

Map of serialized object name to variant data.

[out][transfer container][element-type GVariant GVariant]

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

TRUE on success, FALSE on error, and error +will be set

+
+
+
+
+

ostree_repo_list_commit_objects_starting_with ()

+
gboolean
+ostree_repo_list_commit_objects_starting_with
+                               (OstreeRepo *self,
+                                const char *start,
+                                GHashTable **out_commits,
+                                GCancellable *cancellable,
+                                GError **error);
+

This function synchronously enumerates all commit objects starting +with start +, returning data in out_commits +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

start

List commits starting with this checksum

 

out_commits

Map of serialized commit name to variant data.

[out][transfer container][element-type GVariant GVariant]

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

TRUE on success, FALSE on error, and error +will be set

+
+
+
+
+

ostree_repo_list_static_delta_names ()

+
gboolean
+ostree_repo_list_static_delta_names (OstreeRepo *self,
+                                     GPtrArray **out_deltas,
+                                     GCancellable *cancellable,
+                                     GError **error);
+

This function synchronously enumerates all static deltas in the +repository, returning its result in out_deltas +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

out_deltas

String name of deltas (checksum-checksum.delta).

[out][element-type utf8][transfer container]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_static_delta_generate ()

+
gboolean
+ostree_repo_static_delta_generate (OstreeRepo *self,
+                                   OstreeStaticDeltaGenerateOpt opt,
+                                   const char *from,
+                                   const char *to,
+                                   GVariant *metadata,
+                                   GVariant *params,
+                                   GCancellable *cancellable,
+                                   GError **error);
+

Generate a lookaside "static delta" from from + (NULL means +from-empty) which can generate the objects in to +. This delta is +an optimization over fetching individual objects, and can be +conveniently stored and applied offline.

+

The params + argument should be an a{sv}. The following attributes +are known:

+
    +
  • min-fallback-size: u: Minimum uncompressed size in megabytes to use fallback, 0 to disable fallbacks

  • +
  • max-chunk-size: u: Maximum size in megabytes of a delta part

  • +
  • max-bsdiff-size: u: Maximum size in megabytes to consider bsdiff compression +for input files

  • +
  • compression: y: Compression type: 0=none, x=lzma, g=gzip

  • +
  • bsdiff-enabled: b: Enable bsdiff compression. Default TRUE.

  • +
  • inline-parts: b: Put part data in header, to get a single file delta. Default FALSE.

  • +
  • verbose: b: Print diagnostic messages. Default FALSE.

  • +
  • endianness: b: Deltas use host byte order by default; this option allows choosing (G_BIG_ENDIAN or G_LITTLE_ENDIAN)

  • +
  • filename: ay: Save delta superblock to this filename, and parts in the same directory. Default saves to repository.

  • +
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

opt

High level optimization choice

 

from

ASCII SHA256 checksum of origin, or NULL

 

to

ASCII SHA256 checksum of target

 

metadata

Optional metadata.

[allow-none]

params

Parameters, see below.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_static_delta_execute_offline ()

+
gboolean
+ostree_repo_static_delta_execute_offline
+                               (OstreeRepo *self,
+                                GFile *dir_or_file,
+                                gboolean skip_validation,
+                                GCancellable *cancellable,
+                                GError **error);
+

Given a directory representing an already-downloaded static delta +on disk, apply it, generating a new commit. The directory must be +named with the form "FROM-TO", where both are checksums, and it +must contain a file named "superblock", along with at least one part.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

dir_or_file

Path to a directory containing static delta data, or directly to the superblock

 

skip_validation

If TRUE, assume data integrity

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_traverse_new_reachable ()

+
GHashTable *
+ostree_repo_traverse_new_reachable (void);
+

This hash table is a set of GVariant which can be accessed via +ostree_object_name_deserialize().

+
+

Returns

+

A new hash table.

+

[transfer container][element-type GVariant GVariant]

+
+
+
+
+

ostree_repo_traverse_new_parents ()

+
GHashTable *
+ostree_repo_traverse_new_parents (void);
+

This hash table is a mapping from GVariant which can be accessed +via ostree_object_name_deserialize() to a GVariant containing either +a similar GVariant or and array of them, listing the parents of the key.

+
+

Returns

+

A new hash table.

+

[transfer container][element-type GVariant GVariant]

+
+

Since: 2018.5

+
+
+
+

ostree_repo_traverse_parents_get_commits ()

+
char **
+ostree_repo_traverse_parents_get_commits
+                               (GHashTable *parents,
+                                GVariant *object);
+

Gets all the commits that a certain object belongs to, as recorded +by a parents table gotten from ostree_repo_traverse_commit_union_with_parents.

+
+

Returns

+

An array of checksums for +the commits the key belongs to.

+

[transfer full][array zero-terminated=1]

+
+

Since: 2018.5

+
+
+
+

ostree_repo_traverse_commit ()

+
gboolean
+ostree_repo_traverse_commit (OstreeRepo *repo,
+                             const char *commit_checksum,
+                             int maxdepth,
+                             GHashTable **out_reachable,
+                             GCancellable *cancellable,
+                             GError **error);
+

Create a new set out_reachable + containing all objects reachable +from commit_checksum +, traversing maxdepth + parent commits.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

repo

Repo

 

commit_checksum

ASCII SHA256 checksum

 

maxdepth

Traverse this many parent commits, -1 for unlimited

 

out_reachable

Set of reachable objects.

[out][transfer container][element-type GVariant GVariant]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_traverse_commit_union ()

+
gboolean
+ostree_repo_traverse_commit_union (OstreeRepo *repo,
+                                   const char *commit_checksum,
+                                   int maxdepth,
+                                   GHashTable *inout_reachable,
+                                   GCancellable *cancellable,
+                                   GError **error);
+

Update the set inout_reachable + containing all objects reachable +from commit_checksum +, traversing maxdepth + parent commits.

+

[skip]

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

repo

Repo

 

commit_checksum

ASCII SHA256 checksum

 

maxdepth

Traverse this many parent commits, -1 for unlimited

 

inout_reachable

Set of reachable objects

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_traverse_commit_union_with_parents ()

+
gboolean
+ostree_repo_traverse_commit_union_with_parents
+                               (OstreeRepo *repo,
+                                const char *commit_checksum,
+                                int maxdepth,
+                                GHashTable *inout_reachable,
+                                GHashTable *inout_parents,
+                                GCancellable *cancellable,
+                                GError **error);
+

Update the set inout_reachable + containing all objects reachable +from commit_checksum +, traversing maxdepth + parent commits.

+

Additionally this constructs a mapping from each object to the parents +of the object, which can be used to track which commits an object +belongs to.

+

[skip]

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

repo

Repo

 

commit_checksum

ASCII SHA256 checksum

 

maxdepth

Traverse this many parent commits, -1 for unlimited

 

inout_reachable

Set of reachable objects

 

inout_parents

Map from object to parent object

 

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2018.5

+
+
+
+

ostree_repo_commit_traverse_iter_cleanup ()

+
void
+ostree_repo_commit_traverse_iter_cleanup
+                               (void *p);
+
+
+
+

ostree_repo_commit_traverse_iter_clear ()

+
void
+ostree_repo_commit_traverse_iter_clear
+                               (OstreeRepoCommitTraverseIter *iter);
+
+
+
+

ostree_repo_commit_traverse_iter_get_dir ()

+
void
+ostree_repo_commit_traverse_iter_get_dir
+                               (OstreeRepoCommitTraverseIter *iter,
+                                char **out_name,
+                                char **out_content_checksum,
+                                char **out_meta_checksum);
+

Return information on the current directory. This function may +only be called if OSTREE_REPO_COMMIT_ITER_RESULT_DIR was returned +from ostree_repo_commit_traverse_iter_next().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

iter

An iter

 

out_name

Name of current dir.

[out][transfer none]

out_content_checksum

Checksum of current content.

[out][transfer none]

out_meta_checksum

Checksum of current metadata.

[out][transfer none]
+
+
+
+
+

ostree_repo_commit_traverse_iter_get_file ()

+
void
+ostree_repo_commit_traverse_iter_get_file
+                               (OstreeRepoCommitTraverseIter *iter,
+                                char **out_name,
+                                char **out_checksum);
+

Return information on the current file. This function may only be +called if OSTREE_REPO_COMMIT_ITER_RESULT_FILE was returned from +ostree_repo_commit_traverse_iter_next().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

iter

An iter

 

out_name

Name of current file.

[out][transfer none]

out_checksum

Checksum of current file.

[out][transfer none]
+
+
+
+
+

ostree_repo_commit_traverse_iter_init_commit ()

+
gboolean
+ostree_repo_commit_traverse_iter_init_commit
+                               (OstreeRepoCommitTraverseIter *iter,
+                                OstreeRepo *repo,
+                                GVariant *commit,
+                                OstreeRepoCommitTraverseFlags flags,
+                                GError **error);
+

Initialize (in place) an iterator over the root of a commit object.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

iter

An iter

 

repo

A repo

 

commit

Variant of type OSTREE_OBJECT_TYPE_COMMIT

 

flags

Flags

 

error

Error

 
+
+
+
+
+

ostree_repo_commit_traverse_iter_init_dirtree ()

+
gboolean
+ostree_repo_commit_traverse_iter_init_dirtree
+                               (OstreeRepoCommitTraverseIter *iter,
+                                OstreeRepo *repo,
+                                GVariant *dirtree,
+                                OstreeRepoCommitTraverseFlags flags,
+                                GError **error);
+

Initialize (in place) an iterator over a directory tree.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

iter

An iter

 

repo

A repo

 

dirtree

Variant of type OSTREE_OBJECT_TYPE_DIR_TREE

 

flags

Flags

 

error

Error

 
+
+
+
+
+

ostree_repo_commit_traverse_iter_next ()

+
OstreeRepoCommitIterResult
+ostree_repo_commit_traverse_iter_next (OstreeRepoCommitTraverseIter *iter,
+                                       GCancellable *cancellable,
+                                       GError **error);
+

Step the interator to the next item. Files will be returned first, +then subdirectories. Call this in a loop; upon encountering +OSTREE_REPO_COMMIT_ITER_RESULT_END, there will be no more files or +directories. If OSTREE_REPO_COMMIT_ITER_RESULT_DIR is returned, +then call ostree_repo_commit_traverse_iter_get_dir() to retrieve +data for that directory. Similarly, if +OSTREE_REPO_COMMIT_ITER_RESULT_FILE is returned, call +ostree_repo_commit_traverse_iter_get_file().

+

If OSTREE_REPO_COMMIT_ITER_RESULT_ERROR is returned, it is a +program error to call any further API on iter + except for +ostree_repo_commit_traverse_iter_clear().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

iter

An iter

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_prune ()

+
gboolean
+ostree_repo_prune (OstreeRepo *self,
+                   OstreeRepoPruneFlags flags,
+                   gint depth,
+                   gint *out_objects_total,
+                   gint *out_objects_pruned,
+                   guint64 *out_pruned_object_size_total,
+                   GCancellable *cancellable,
+                   GError **error);
+

Delete content from the repository. By default, this function will +only delete "orphaned" objects not referred to by any commit. This +can happen during a local commit operation, when we have written +content objects but not saved the commit referencing them.

+

However, if OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY is provided, instead +of traversing all commits, only refs will be used. Particularly +when combined with depth +, this is a convenient way to delete +history from the repository.

+

Use the OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE to just determine +statistics on objects that would be deleted, without actually +deleting them.

+

Locking: exclusive

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

flags

Options controlling prune process

 

depth

Stop traversal after this many iterations (-1 for unlimited)

 

out_objects_total

Number of objects found.

[out]

out_objects_pruned

Number of objects deleted.

[out]

out_pruned_object_size_total

Storage size in bytes of objects deleted.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_prune_static_deltas ()

+
gboolean
+ostree_repo_prune_static_deltas (OstreeRepo *self,
+                                 const char *commit,
+                                 GCancellable *cancellable,
+                                 GError **error);
+

Prune static deltas, if COMMIT is specified then delete static delta files only +targeting that commit; otherwise any static delta of non existing commits are +deleted.

+

Locking: exclusive

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

commit

ASCII SHA256 checksum for commit, or NULL for each +non existing commit.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_traverse_reachable_refs ()

+
gboolean
+ostree_repo_traverse_reachable_refs (OstreeRepo *self,
+                                     guint depth,
+                                     GHashTable *reachable,
+                                     GCancellable *cancellable,
+                                     GError **error);
+

Add all commit objects directly reachable via a ref to reachable +.

+

Locking: shared

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

depth

Depth of traversal

 

reachable

Set of reachable objects (will be modified).

[element-type GVariant GVariant]

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2018.6

+
+
+
+

ostree_repo_prune_from_reachable ()

+
gboolean
+ostree_repo_prune_from_reachable (OstreeRepo *self,
+                                  OstreeRepoPruneOptions *options,
+                                  gint *out_objects_total,
+                                  gint *out_objects_pruned,
+                                  guint64 *out_pruned_object_size_total,
+                                  GCancellable *cancellable,
+                                  GError **error);
+

Delete content from the repository. This function is the "backend" +half of the higher level ostree_repo_prune(). To use this function, +you determine the root set yourself, and this function finds all other +unreferenced objects and deletes them.

+

Use this API when you want to perform more selective pruning - for example, +retain all commits from a production branch, but just GC some history from +your dev branch.

+

The OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE flag may be specified to just determine +statistics on objects that would be deleted, without actually deleting them.

+

Locking: exclusive

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

options

Options controlling prune process

 

out_objects_total

Number of objects found.

[out]

out_objects_pruned

Number of objects deleted.

[out]

out_pruned_object_size_total

Storage size in bytes of objects deleted.

[out]

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2017.1

+
+
+
+

ostree_repo_pull ()

+
gboolean
+ostree_repo_pull (OstreeRepo *self,
+                  const char *remote_name,
+                  char **refs_to_fetch,
+                  OstreeRepoPullFlags flags,
+                  OstreeAsyncProgress *progress,
+                  GCancellable *cancellable,
+                  GError **error);
+

Connect to the remote repository, fetching the specified set of +refs refs_to_fetch +. For each ref that is changed, download the +commit, all metadata, and all content objects, storing them safely +on disk in self +.

+

If flags + contains OSTREE_REPO_PULL_FLAGS_MIRROR, and +the refs_to_fetch + is NULL, and the remote repository contains a +summary file, then all refs will be fetched.

+

If flags + contains OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY, then only the +metadata for the commits in refs_to_fetch + is pulled.

+

Warning: This API will iterate the thread default main context, +which is a bug, but kept for compatibility reasons. If you want to +avoid this, use g_main_context_push_thread_default() to push a new +one around this call.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

remote_name

Name of remote

 

refs_to_fetch

Optional list of refs; if NULL, fetch all configured refs.

[array zero-terminated=1][element-type utf8][allow-none]

flags

Options controlling fetch behavior

 

progress

Progress.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_pull_one_dir ()

+
gboolean
+ostree_repo_pull_one_dir (OstreeRepo *self,
+                          const char *remote_name,
+                          const char *dir_to_pull,
+                          char **refs_to_fetch,
+                          OstreeRepoPullFlags flags,
+                          OstreeAsyncProgress *progress,
+                          GCancellable *cancellable,
+                          GError **error);
+

This is similar to ostree_repo_pull(), but only fetches a single +subpath.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

remote_name

Name of remote

 

dir_to_pull

Subdirectory path

 

refs_to_fetch

Optional list of refs; if NULL, fetch all configured refs.

[array zero-terminated=1][element-type utf8][allow-none]

flags

Options controlling fetch behavior

 

progress

Progress.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_pull_with_options ()

+
gboolean
+ostree_repo_pull_with_options (OstreeRepo *self,
+                               const char *remote_name_or_baseurl,
+                               GVariant *options,
+                               OstreeAsyncProgress *progress,
+                               GCancellable *cancellable,
+                               GError **error);
+

Like ostree_repo_pull(), but supports an extensible set of flags. +The following are currently defined:

+
    +
  • refs (as): Array of string refs

  • +
  • collection-refs (a(sss)): Array of (collection ID, ref name, checksum) tuples to pull; +mutually exclusive with refs and override-commit-ids. Checksums may be the empty +string to pull the latest commit for that ref

  • +
  • flags (i): An instance of OstreeRepoPullFlags

  • +
  • subdir (s): Pull just this subdirectory

  • +
  • subdirs (as): Pull just these subdirectories

  • +
  • override-remote-name (s): If local, add this remote to refspec

  • +
  • gpg-verify (b): GPG verify commits

  • +
  • gpg-verify-summary (b): GPG verify summary

  • +
  • disable-sign-verify (b): Disable signapi verification of commits

  • +
  • disable-sign-verify-summary (b): Disable signapi verification of the summary

  • +
  • depth (i): How far in the history to traverse; default is 0, -1 means infinite

  • +
  • per-object-fsync (b): Perform disk writes more slowly, avoiding a single large I/O sync

  • +
  • disable-static-deltas (b): Do not use static deltas

  • +
  • require-static-deltas (b): Require static deltas

  • +
  • override-commit-ids (as): Array of specific commit IDs to fetch for refs

  • +
  • timestamp-check (b): Verify commit timestamps are newer than current (when pulling via ref); Since: 2017.11

  • +
  • timestamp-check-from-rev (s): Verify that all fetched commit timestamps are newer than timestamp of given rev; Since: 2020.4

  • +
  • metadata-size-restriction (t): Restrict metadata objects to a maximum number of bytes; 0 to disable. Since: 2018.9

  • +
  • dry-run (b): Only print information on what will be downloaded (requires static deltas)

  • +
  • override-url (s): Fetch objects from this URL if remote specifies no metalink in options

  • +
  • inherit-transaction (b): Don't initiate, finish or abort a transaction, useful to do multiple pulls in one transaction.

  • +
  • http-headers (a(ss)): Additional headers to add to all HTTP requests

  • +
  • update-frequency (u): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid

  • +
  • localcache-repos (as): File paths for local repos to use as caches when doing remote fetches

  • +
  • append-user-agent (s): Additional string to append to the user agent

  • +
  • n-network-retries (u): Number of times to retry each download on receiving +a transient network error, such as a socket timeout; default is 5, 0 +means return errors without retrying. Since: 2018.6

  • +
  • ref-keyring-map (a(sss)): Array of (collection ID, ref name, keyring +remote name) tuples specifying which remote's keyring should be used when +doing GPG verification of each collection-ref. This is useful to prevent a +remote from serving malicious updates to refs which did not originate from +it. This can be a subset or superset of the refs being pulled; any ref +not being pulled will be ignored and any ref without a keyring remote +will be verified with the keyring of the remote being pulled from.

  • +
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

remote_name_or_baseurl

Name of remote or file:// url

 

options

A GVariant a{sv} with an extensible set of flags.

 

progress

Progress.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2019.2

+
+
+
+

ostree_repo_pull_default_console_progress_changed ()

+
void
+ostree_repo_pull_default_console_progress_changed
+                               (OstreeAsyncProgress *progress,
+                                gpointer user_data);
+

Convenient "changed" callback for use with +ostree_async_progress_new_and_connect() when pulling from a remote +repository.

+

Depending on the state of the OstreeAsyncProgress, either displays a +custom status message, or else outstanding fetch progress in bytes/sec, +or else outstanding content or metadata writes to the repository in +number of objects.

+

Compatibility note: this function previously assumed that user_data + +was a pointer to a GSConsole instance. This is no longer the case, +and user_data + is ignored.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

progress

Async progress

 

user_data

User data.

[allow-none]
+
+
+
+
+

ostree_repo_sign_commit ()

+
gboolean
+ostree_repo_sign_commit (OstreeRepo *self,
+                         const gchar *commit_checksum,
+                         const gchar *key_id,
+                         const gchar *homedir,
+                         GCancellable *cancellable,
+                         GError **error);
+

Add a GPG signature to a commit.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

commit_checksum

SHA256 of given commit to sign

 

key_id

Use this GPG key id

 

homedir

GPG home directory, or NULL.

[allow-none]

cancellable

A GCancellable

 

error

a GError

 
+
+
+
+
+

ostree_repo_append_gpg_signature ()

+
gboolean
+ostree_repo_append_gpg_signature (OstreeRepo *self,
+                                  const gchar *commit_checksum,
+                                  GBytes *signature_bytes,
+                                  GCancellable *cancellable,
+                                  GError **error);
+

Append a GPG signature to a commit.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

commit_checksum

SHA256 of given commit to sign

 

signature_bytes

Signature data

 

cancellable

A GCancellable

 

error

a GError

 
+
+
+
+
+

ostree_repo_add_gpg_signature_summary ()

+
gboolean
+ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
+                                       const gchar **key_id,
+                                       const gchar *homedir,
+                                       GCancellable *cancellable,
+                                       GError **error);
+

Add a GPG signature to a summary file.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

key_id

NULL-terminated array of GPG keys.

[array zero-terminated=1][element-type utf8]

homedir

GPG home directory, or NULL.

[allow-none]

cancellable

A GCancellable

 

error

a GError

 
+
+
+
+
+

ostree_repo_gpg_verify_data ()

+
OstreeGpgVerifyResult *
+ostree_repo_gpg_verify_data (OstreeRepo *self,
+                             const gchar *remote_name,
+                             GBytes *data,
+                             GBytes *signatures,
+                             GFile *keyringdir,
+                             GFile *extra_keyring,
+                             GCancellable *cancellable,
+                             GError **error);
+

Verify signatures + for data + using GPG keys in the keyring for +remote_name +, and return an OstreeGpgVerifyResult.

+

The remote_name + parameter can be NULL. In that case it will do +the verifications using GPG keys in the keyrings of all remotes.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repository

 

remote_name

Name of remote.

[nullable]

data

Data as a GBytes

 

signatures

Signatures as a GBytes

 

keyringdir

Path to directory GPG keyrings; overrides built-in default if given.

[nullable]

extra_keyring

Path to additional keyring file (not a directory).

[nullable]

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

an OstreeGpgVerifyResult, or NULL on error.

+

[transfer full]

+
+

Since: 2016.6

+
+
+
+

ostree_repo_verify_commit ()

+
gboolean
+ostree_repo_verify_commit (OstreeRepo *self,
+                           const gchar *commit_checksum,
+                           GFile *keyringdir,
+                           GFile *extra_keyring,
+                           GCancellable *cancellable,
+                           GError **error);
+

Check for a valid GPG signature on commit named by the ASCII +checksum commit_checksum +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repository

 

commit_checksum

ASCII SHA256 checksum

 

keyringdir

Path to directory GPG keyrings; overrides built-in default if given.

[allow-none]

extra_keyring

Path to additional keyring file (not a directory).

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

TRUE if there was a GPG signature from a trusted keyring, otherwise FALSE

+
+
+
+
+

ostree_repo_verify_commit_ext ()

+
OstreeGpgVerifyResult *
+ostree_repo_verify_commit_ext (OstreeRepo *self,
+                               const gchar *commit_checksum,
+                               GFile *keyringdir,
+                               GFile *extra_keyring,
+                               GCancellable *cancellable,
+                               GError **error);
+

Read GPG signature(s) on the commit named by the ASCII checksum +commit_checksum + and return detailed results.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repository

 

commit_checksum

ASCII SHA256 checksum

 

keyringdir

Path to directory GPG keyrings; overrides built-in default if given.

[allow-none]

extra_keyring

Path to additional keyring file (not a directory).

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

an OstreeGpgVerifyResult, or NULL on error.

+

[transfer full]

+
+
+
+
+

ostree_repo_verify_commit_for_remote ()

+
OstreeGpgVerifyResult *
+ostree_repo_verify_commit_for_remote (OstreeRepo *self,
+                                      const gchar *commit_checksum,
+                                      const gchar *remote_name,
+                                      GCancellable *cancellable,
+                                      GError **error);
+

Read GPG signature(s) on the commit named by the ASCII checksum +commit_checksum + and return detailed results, based on the keyring +configured for remote +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repository

 

commit_checksum

ASCII SHA256 checksum

 

remote_name

OSTree remote to use for configuration

 

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

an OstreeGpgVerifyResult, or NULL on error.

+

[transfer full]

+
+

Since: 2016.14

+
+
+
+

ostree_repo_verify_summary ()

+
OstreeGpgVerifyResult *
+ostree_repo_verify_summary (OstreeRepo *self,
+                            const char *remote_name,
+                            GBytes *summary,
+                            GBytes *signatures,
+                            GCancellable *cancellable,
+                            GError **error);
+

Verify signatures + for summary + data using GPG keys in the keyring for +remote_name +, and return an OstreeGpgVerifyResult.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

remote_name

Name of remote

 

summary

Summary data as a GBytes

 

signatures

Summary signatures as a GBytes

 

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

an OstreeGpgVerifyResult, or NULL on error.

+

[transfer full]

+
+
+
+
+

ostree_repo_regenerate_summary ()

+
gboolean
+ostree_repo_regenerate_summary (OstreeRepo *self,
+                                GVariant *additional_metadata,
+                                GCancellable *cancellable,
+                                GError **error);
+

An OSTree repository can contain a high level "summary" file that +describes the available branches and other metadata.

+

If the timetable for making commits and updating the summary file is fairly +regular, setting the ostree.summary.expires key in additional_metadata + +will aid clients in working out when to check for updates.

+

It is regenerated automatically after any ref is +added, removed, or updated if core/auto-update-summary is set.

+

If the core/collection-id key is set in the configuration, it will be +included as OSTREE_SUMMARY_COLLECTION_ID in the summary file. Refs that +have associated collection IDs will be included in the generated summary +file, listed under the OSTREE_SUMMARY_COLLECTION_MAP key. Collection IDs +and refs in OSTREE_SUMMARY_COLLECTION_MAP are guaranteed to be in +lexicographic order.

+

Locking: exclusive

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

additional_metadata

A GVariant of type a{sv}, or NULL.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

Types and Values

+
+

OstreeRepo

+
typedef struct OstreeRepo OstreeRepo;
+
+

Private instance structure.

+
+
+
+

enum OstreeRepoMode

+

See the documentation of OstreeRepo for more information about the +possible modes.

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_REPO_MODE_BARE

+

Files are stored as themselves; checkouts are hardlinks; can only be written as root

+
 

OSTREE_REPO_MODE_ARCHIVE

+

Files are compressed, should be owned by non-root. Can be served via HTTP. Since: 2017.12

+
 

OSTREE_REPO_MODE_ARCHIVE_Z2

+

Legacy alias for OSTREE_REPO_MODE_ARCHIVE

+
 

OSTREE_REPO_MODE_BARE_USER

+

Files are stored as themselves, except ownership; can be written by user. Hardlinks work only in user checkouts.

+
 

OSTREE_REPO_MODE_BARE_USER_ONLY

+

Same as BARE_USER, but all metadata is not stored, so it can only be used for user checkouts. Does not need xattrs.

+
 
+
+
+
+
+

enum OstreeRepoRemoteChange

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_REPO_REMOTE_CHANGE_ADD

+

Add a remote

+
 

OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS

+

Like above, but do nothing if the remote exists

+
 

OSTREE_REPO_REMOTE_CHANGE_DELETE

+

Delete a remote

+
 

OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS

+

Delete a remote, do nothing if the remote does not exist

+
 

OSTREE_REPO_REMOTE_CHANGE_REPLACE

+

Add or replace a remote (Since: 2019.2)

+
 
+
+
+
+
+

struct OstreeRepoTransactionStats

+
struct OstreeRepoTransactionStats {
+  guint metadata_objects_total;
+  guint metadata_objects_written;
+  guint content_objects_total;
+  guint content_objects_written;
+  guint64 content_bytes_written;
+  guint devino_cache_hits;
+
+  guint   padding1;
+  guint64 padding2;
+  guint64 padding3;
+  guint64 padding4;
+};
+
+

A list of statistics for each transaction that may be +interesting for reporting purposes.

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

guint metadata_objects_total;

The total number of metadata objects +in the repository after this transaction has completed.

 

guint metadata_objects_written;

The number of metadata objects that +were written to the repository in this transaction.

 

guint content_objects_total;

The total number of content objects +in the repository after this transaction has completed.

 

guint content_objects_written;

The number of content objects that +were written to the repository in this transaction.

 

guint64 content_bytes_written;

The amount of data added to the repository, +in bytes, counting only content objects.

 

guint devino_cache_hits;

  

guint padding1;

reserved

 

guint64 padding2;

reserved

 

guint64 padding3;

reserved

 

guint64 padding4;

reserved

 
+
+
+
+
+

enum OstreeRepoResolveRevExtFlags

+
+

Members

+
+++++ + + + + + + + + + + + + +

OSTREE_REPO_RESOLVE_REV_EXT_NONE

+

No flags.

+
 

OSTREE_REPO_RESOLVE_REV_EXT_LOCAL_ONLY

+

Exclude remote and mirrored refs. Since: 2019.2

+
 
+
+
+
+
+

enum OstreeRepoListRefsExtFlags

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_REPO_LIST_REFS_EXT_NONE

+

No flags.

+
 

OSTREE_REPO_LIST_REFS_EXT_ALIASES

+

Only list aliases. Since: 2017.10

+
 

OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES

+

Exclude remote refs. Since: 2017.11

+
 

OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_MIRRORS

+

Exclude mirrored refs. Since: 2019.2

+
 
+
+
+
+
+

enum OstreeRepoCommitState

+

Flags representing the state of a commit in the local repository, as returned +by ostree_repo_load_commit().

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + +

OSTREE_REPO_COMMIT_STATE_NORMAL

+

Commit is complete. This is the default. +(Since: 2017.14.)

+
 

OSTREE_REPO_COMMIT_STATE_PARTIAL

+

One or more objects are missing from the +local copy of the commit, but metadata is present. (Since: 2015.7.)

+
 

OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL

+

One or more objects are missing from the +local copy of the commit, due to an fsck --delete. (Since: 2019.4.)

+
 
+
+

Since: 2015.7

+
+
+
+

enum OstreeRepoCommitFilterResult

+
+

Members

+
+++++ + + + + + + + + + + + + +

OSTREE_REPO_COMMIT_FILTER_ALLOW

+

Do commit this object

+
 

OSTREE_REPO_COMMIT_FILTER_SKIP

+

Ignore this object

+
 
+
+
+
+
+

OstreeRepoCommitModifier

+
typedef struct OstreeRepoCommitModifier OstreeRepoCommitModifier;
+
+

A structure allowing control over commits.

+
+
+
+

enum OstreeRepoCommitModifierFlags

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_REPO_COMMIT_MODIFIER_FLAGS_NONE

+

No special flags

+
 

OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS

+

Do not process extended attributes

+
 

OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES

+

Generate size information.

+
 

OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS

+

Canonicalize permissions for bare-user-only mode.

+
 

OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED

+

Emit an error if configured SELinux policy does not provide a label

+
 

OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME

+

Delete added files/directories after commit; Since: 2017.13

+
 

OSTREE_REPO_COMMIT_MODIFIER_FLAGS_DEVINO_CANONICAL

+

If a devino cache hit is found, skip modifier filters (non-directories only); Since: 2017.14

+
 
+
+
+
+
+

OstreeRepoCheckoutAtOptions

+
typedef struct {
+  OstreeRepoCheckoutMode mode;
+  OstreeRepoCheckoutOverwriteMode overwrite_mode;
+
+  gboolean enable_uncompressed_cache;  /* Deprecated */
+  gboolean enable_fsync;  /* Deprecated */
+  gboolean process_whiteouts;
+  gboolean no_copy_fallback;
+  gboolean force_copy; /* Since: 2017.6 */
+  gboolean bareuseronly_dirs; /* Since: 2017.7 */
+  gboolean force_copy_zerosized; /* Since: 2018.9 */
+  gboolean unused_bools[4];
+  /* 4 byte hole on 64 bit */
+
+  const char *subpath;
+
+  OstreeRepoDevInoCache *devino_to_csum_cache;
+
+  int unused_ints[6];
+  gpointer unused_ptrs[3];
+  OstreeRepoCheckoutFilter filter; /* Since: 2018.2 */
+  gpointer filter_user_data; /* Since: 2018.2 */
+  OstreeSePolicy *sepolicy; /* Since: 2017.6 */
+  const char *sepolicy_prefix;
+} OstreeRepoCheckoutAtOptions;
+
+

An extensible options structure controlling checkout. Ensure that +you have entirely zeroed the structure, then set just the desired +options. This is used by ostree_repo_checkout_at() which +supercedes previous separate enumeration usage in +ostree_repo_checkout_tree() and ostree_repo_checkout_tree_at().

+
+
+
+

enum OstreeRepoCheckoutMode

+
+

Members

+
+++++ + + + + + + + + + + + + +

OSTREE_REPO_CHECKOUT_MODE_NONE

+

No special options

+
 

OSTREE_REPO_CHECKOUT_MODE_USER

+

Ignore uid/gid of files

+
 
+
+
+
+
+

enum OstreeRepoCheckoutOverwriteMode

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_REPO_CHECKOUT_OVERWRITE_NONE

+

No special options

+
 

OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES

+

When layering checkouts, unlink() and replace existing files, but do not modify existing directories (unless whiteouts are enabled, then directories are replaced)

+
 

OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES

+

Only add new files/directories

+
 

OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL

+

Like UNION_FILES, but error if files are not identical (requires hardlink checkouts)

+
 
+
+
+
+
+

enum OstreeRepoListObjectsFlags

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_REPO_LIST_OBJECTS_LOOSE

+

List only loose (plain file) objects

+
 

OSTREE_REPO_LIST_OBJECTS_PACKED

+

List only packed (compacted into blobs) objects

+
 

OSTREE_REPO_LIST_OBJECTS_ALL

+

List all objects

+
 

OSTREE_REPO_LIST_OBJECTS_NO_PARENTS

+

Only list objects in this repo, not parents

+
 
+
+
+
+
+

OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE

+
#define OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE (G_VARIANT_TYPE ("(bas)")
+
+

b - TRUE if object is available "loose" +as - List of pack file checksums in which this object appears

+
+
+
+

enum OstreeStaticDeltaGenerateOpt

+

Parameters controlling optimization of static deltas.

+
+

Members

+
+++++ + + + + + + + + + + + + +

OSTREE_STATIC_DELTA_GENERATE_OPT_LOWLATENCY

+

Optimize for speed of delta creation over space

+
 

OSTREE_STATIC_DELTA_GENERATE_OPT_MAJOR

+

Optimize for delta size (may be very slow)

+
 
+
+
+
+
+

enum OstreeRepoCommitTraverseFlags

+
+

Members

+
+++++ + + + + + +

OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE

  
+
+
+
+
+

enum OstreeRepoCommitIterResult

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_REPO_COMMIT_ITER_RESULT_ERROR

  

OSTREE_REPO_COMMIT_ITER_RESULT_END

  

OSTREE_REPO_COMMIT_ITER_RESULT_FILE

  

OSTREE_REPO_COMMIT_ITER_RESULT_DIR

  
+
+
+
+
+

enum OstreeRepoPruneFlags

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + +

OSTREE_REPO_PRUNE_FLAGS_NONE

+

No special options for pruning

+
 

OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE

+

Don't actually delete objects

+
 

OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY

+

Do not traverse individual commit objects, only follow refs

+
 
+
+
+
+
+

enum OstreeRepoPullFlags

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_REPO_PULL_FLAGS_NONE

+

No special options for pull

+
 

OSTREE_REPO_PULL_FLAGS_MIRROR

+

Write out refs suitable for mirrors and fetch all refs if none requested

+
 

OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY

+

Fetch only the commit metadata

+
 

OSTREE_REPO_PULL_FLAGS_UNTRUSTED

+

Do verify checksums of local (filesystem-accessible) repositories (defaults on for HTTP)

+
 

OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES

+

Since 2017.7. Reject writes of content objects with modes outside of 0775.

+
 

OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP

+

Don't verify checksums of objects HTTP repositories (Since: 2017.12)

+
 
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html b/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html new file mode 100644 index 0000000..398043d --- /dev/null +++ b/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html @@ -0,0 +1,594 @@ + + + + +Progress notification system for asynchronous operations: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

Progress notification system for asynchronous operations

+

Progress notification system for asynchronous operations — Values representing progress

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+OstreeAsyncProgress * + +ostree_async_progress_new () +
+OstreeAsyncProgress * + +ostree_async_progress_new_and_connect () +
+void + +ostree_async_progress_copy_state () +
+char * + +ostree_async_progress_get_status () +
+void + +ostree_async_progress_get () +
+GVariant * + +ostree_async_progress_get_variant () +
+guint + +ostree_async_progress_get_uint () +
+guint64 + +ostree_async_progress_get_uint64 () +
+void + +ostree_async_progress_set_status () +
+void + +ostree_async_progress_set () +
+void + +ostree_async_progress_set_variant () +
+void + +ostree_async_progress_set_uint () +
+void + +ostree_async_progress_set_uint64 () +
+void + +ostree_async_progress_finish () +
+
+
+

Types and Values

+
++++ + + + + +
typedefOstreeAsyncProgress
+
+
+

Description

+

For many asynchronous operations, it's desirable for callers to be +able to watch their status as they progress. For example, an user +interface calling an asynchronous download operation will want to +be able to see the total number of bytes downloaded.

+

This class provides a mechanism for callees of asynchronous +operations to communicate back with callers. It transparently +handles thread safety, ensuring that the progress change +notification occurs in the thread-default context of the calling +operation.

+

The ostree_async_progress_get_status() and ostree_async_progress_set_status() +methods get and set a well-known status key of type G_VARIANT_TYPE_STRING. +This key may be accessed using the other OstreeAsyncProgress methods, but it +must always have the correct type.

+
+
+

Functions

+
+

ostree_async_progress_new ()

+
OstreeAsyncProgress *
+ostree_async_progress_new (void);
+
+

Returns

+

A new progress object.

+

[transfer full]

+
+
+
+
+

ostree_async_progress_new_and_connect ()

+
OstreeAsyncProgress *
+ostree_async_progress_new_and_connect (void (*changed) (OstreeAsyncProgress *self, gpointer user_data),
+                                       gpointer user_data);
+
+
+
+

ostree_async_progress_copy_state ()

+
void
+ostree_async_progress_copy_state (OstreeAsyncProgress *self,
+                                  OstreeAsyncProgress *dest);
+

Atomically copies all the state from self + to dest +, without invoking the +callback. +This is used for proxying progress objects across different GMainContexts.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

An OstreeAsyncProgress to copy from

 

dest

An OstreeAsyncProgress to copy to

 
+
+

Since: 2019.6

+
+
+
+

ostree_async_progress_get_status ()

+
char *
+ostree_async_progress_get_status (OstreeAsyncProgress *self);
+

Get the human-readable status string from the OstreeAsyncProgress. This +operation is thread-safe. The retuned value may be NULL if no status is +set.

+

This is a convenience function to get the well-known status key.

+
+

Parameters

+
+++++ + + + + + +

self

an OstreeAsyncProgress

 
+
+
+

Returns

+

the current status, or NULL if none is set.

+

[transfer full][nullable]

+
+

Since: 2017.6

+
+
+
+

ostree_async_progress_get ()

+
void
+ostree_async_progress_get (OstreeAsyncProgress *self,
+                           ...);
+

Get the values corresponding to zero or more keys from the +OstreeAsyncProgress. Each key is specified in @... as the key name, followed +by a GVariant format string, followed by the necessary arguments for that +format string, just as for g_variant_get(). After those arguments is the +next key name. The varargs list must be NULL-terminated.

+

Each format string must make deep copies of its value, as the values stored +in the OstreeAsyncProgress may be freed from another thread after this +function returns.

+

This operation is thread-safe, and all the keys are queried atomically.

+
+ + + + + + + +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
guint32 outstanding_fetches;
+guint64 bytes_received;
+g_autofree gchar *status = NULL;
+g_autoptr(GVariant) refs_variant = NULL;
+
+ostree_async_progress_get (progress,
+                           "outstanding-fetches", "u", &outstanding_fetches,
+                           "bytes-received", "t", &bytes_received,
+                           "status", "s", &status,
+                           "refs", "@a{ss}", &refs_variant,
+                           NULL);
+
+ +

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

an OstreeAsyncProgress

 

...

key name, format string, GVariant return locations, …, followed by NULL

 
+
+

Since: 2017.6

+
+
+
+

ostree_async_progress_get_variant ()

+
GVariant *
+ostree_async_progress_get_variant (OstreeAsyncProgress *self,
+                                   const char *key);
+

Look up a key in the OstreeAsyncProgress and return the GVariant associated +with it. The lookup is thread-safe.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

an OstreeAsyncProgress

 

key

a key to look up

 
+
+
+

Returns

+

value for the given key +, or NULL if +it was not set.

+

[transfer full][nullable]

+
+

Since: 2017.6

+
+
+
+

ostree_async_progress_get_uint ()

+
guint
+ostree_async_progress_get_uint (OstreeAsyncProgress *self,
+                                const char *key);
+
+
+
+

ostree_async_progress_get_uint64 ()

+
guint64
+ostree_async_progress_get_uint64 (OstreeAsyncProgress *self,
+                                  const char *key);
+
+
+
+

ostree_async_progress_set_status ()

+
void
+ostree_async_progress_set_status (OstreeAsyncProgress *self,
+                                  const char *status);
+

Set the human-readable status string for the OstreeAsyncProgress. This +operation is thread-safe. NULL may be passed to clear the status.

+

This is a convenience function to set the well-known status key.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

an OstreeAsyncProgress

 

status

new status string, or NULL to clear the status.

[nullable]
+
+

Since: 2017.6

+
+
+
+

ostree_async_progress_set ()

+
void
+ostree_async_progress_set (OstreeAsyncProgress *self,
+                           ...);
+

Set the values for zero or more keys in the OstreeAsyncProgress. Each key is +specified in @... as the key name, followed by a GVariant format string, +followed by the necessary arguments for that format string, just as for +g_variant_new(). After those arguments is the next key name. The varargs list +must be NULL-terminated.

+

g_variant_ref_sink() will be called as appropriate on the GVariant +parameters, so they may be floating.

+

This operation is thread-safe, and all the keys are set atomically.

+
+ + + + + + + +
1
+2
+3
+4
+5
+6
+7
+8
+9
guint32 outstanding_fetches = 15;
+guint64 bytes_received = 1000;
+
+ostree_async_progress_set (progress,
+                           "outstanding-fetches", "u", outstanding_fetches,
+                           "bytes-received", "t", bytes_received,
+                           "status", "s", "Updated status",
+                           "refs", "@a{ss}", g_variant_new_parsed ("@a{ss} {}"),
+                           NULL);
+
+ +

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

an OstreeAsyncProgress

 

...

key name, format string, GVariant parameters, …, followed by NULL

 
+
+

Since: 2017.6

+
+
+
+

ostree_async_progress_set_variant ()

+
void
+ostree_async_progress_set_variant (OstreeAsyncProgress *self,
+                                   const char *key,
+                                   GVariant *value);
+

Assign a new value + to the given key +, replacing any existing value. The +operation is thread-safe. value + may be a floating reference; +g_variant_ref_sink() will be called on it.

+

Any watchers of the OstreeAsyncProgress will be notified of the change if +value + differs from the existing value for key +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

an OstreeAsyncProgress

 

key

a key to set

 

value

the value to assign to key +

 
+
+

Since: 2017.6

+
+
+
+

ostree_async_progress_set_uint ()

+
void
+ostree_async_progress_set_uint (OstreeAsyncProgress *self,
+                                const char *key,
+                                guint value);
+
+
+
+

ostree_async_progress_set_uint64 ()

+
void
+ostree_async_progress_set_uint64 (OstreeAsyncProgress *self,
+                                  const char *key,
+                                  guint64 value);
+
+
+
+

ostree_async_progress_finish ()

+
void
+ostree_async_progress_finish (OstreeAsyncProgress *self);
+

Process any pending signals, ensuring the main context is cleared +of sources used by this object. Also ensures that no further +events will be queued.

+
+

Parameters

+
+++++ + + + + + +

self

Self

 
+
+
+
+
+

Types and Values

+
+

OstreeAsyncProgress

+
typedef struct OstreeAsyncProgress   OstreeAsyncProgress;
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-Root-partition-mount-point.html b/apidoc/html/ostree-Root-partition-mount-point.html new file mode 100644 index 0000000..3b1b106 --- /dev/null +++ b/apidoc/html/ostree-Root-partition-mount-point.html @@ -0,0 +1,2130 @@ + + + + +Root partition mount point: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

Root partition mount point

+

Root partition mount point — Manage physical root filesystem

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+OstreeSysroot * + +ostree_sysroot_new () +
+OstreeSysroot * + +ostree_sysroot_new_default () +
+gboolean + +ostree_sysroot_initialize () +
+GFile * + +ostree_sysroot_get_path () +
+gboolean + +ostree_sysroot_load () +
+gboolean + +ostree_sysroot_load_if_changed () +
+gboolean + +ostree_sysroot_lock () +
+gboolean + +ostree_sysroot_try_lock () +
+void + +ostree_sysroot_lock_async () +
+gboolean + +ostree_sysroot_lock_finish () +
+void + +ostree_sysroot_unlock () +
+void + +ostree_sysroot_unload () +
+void + +ostree_sysroot_set_mount_namespace_in_use () +
+gboolean + +ostree_sysroot_is_booted () +
+int + +ostree_sysroot_get_fd () +
+gboolean + +ostree_sysroot_ensure_initialized () +
+int + +ostree_sysroot_get_bootversion () +
+int + +ostree_sysroot_get_subbootversion () +
+GPtrArray * + +ostree_sysroot_get_deployments () +
+OstreeDeployment * + +ostree_sysroot_get_booted_deployment () +
+GFile * + +ostree_sysroot_get_deployment_directory () +
+char * + +ostree_sysroot_get_deployment_dirpath () +
+GFile * + +ostree_sysroot_get_deployment_origin_path () +
+gboolean + +ostree_sysroot_cleanup () +
+gboolean + +ostree_sysroot_prepare_cleanup () +
+gboolean + +ostree_sysroot_cleanup_prune_repo () +
+OstreeRepo * + +ostree_sysroot_repo () +
+gboolean + +ostree_sysroot_get_repo () +
+OstreeDeployment * + +ostree_sysroot_get_staged_deployment () +
+gboolean + +ostree_sysroot_init_osname () +
+gboolean + +ostree_sysroot_deployment_set_kargs () +
+gboolean + +ostree_sysroot_deployment_set_mutable () +
+gboolean + +ostree_sysroot_deployment_unlock () +
+gboolean + +ostree_sysroot_deployment_set_pinned () +
+gboolean + +ostree_sysroot_write_deployments () +
+gboolean + +ostree_sysroot_write_deployments_with_options () +
+gboolean + +ostree_sysroot_write_origin_file () +
+gboolean + +ostree_sysroot_stage_tree () +
+gboolean + +ostree_sysroot_deploy_tree () +
+OstreeDeployment * + +ostree_sysroot_get_merge_deployment () +
+void + +ostree_sysroot_query_deployments_for () +
+GKeyFile * + +ostree_sysroot_origin_new_from_refspec () +
+gboolean + +ostree_sysroot_simple_write_deployment () +
+
+
+

Types and Values

+
++++ + + + + + + + + + + +
typedefOstreeSysroot
enumOstreeSysrootSimpleWriteDeploymentFlags
+
+
+

Description

+

A OstreeSysroot object represents a physical root filesystem, +which in particular should contain a toplevel /ostree directory. +Inside this directory is an OstreeRepo in /ostree/repo, plus a set +of deployments in /ostree/deploy.

+

This class is not by default safe against concurrent use by threads +or external processes. You can use ostree_sysroot_lock() to +perform locking externally.

+
+
+

Functions

+
+

ostree_sysroot_new ()

+
OstreeSysroot *
+ostree_sysroot_new (GFile *path);
+

Create a new OstreeSysroot object for the sysroot at path +. If path + is NULL, +the current visible root file system is used, equivalent to +ostree_sysroot_new_default().

+
+

Parameters

+
+++++ + + + + + +

path

Path to a system root directory, or NULL to use the +current visible root file system.

[allow-none]
+
+
+

Returns

+

An accessor object for an system root located at path +.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_new_default ()

+
OstreeSysroot *
+ostree_sysroot_new_default (void);
+
+

Returns

+

An accessor for the current visible root / filesystem.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_initialize ()

+
gboolean
+ostree_sysroot_initialize (OstreeSysroot *self,
+                           GError **error);
+

Subset of ostree_sysroot_load(); performs basic initialization. Notably, one +can invoke ostree_sysroot_get_fd() after calling this function.

+

It is not necessary to call this function if ostree_sysroot_load() is +invoked.

+
+

Parameters

+
+++++ + + + + + +

self

sysroot

 
+
+

Since: 2020.1

+
+
+
+

ostree_sysroot_get_path ()

+
GFile *
+ostree_sysroot_get_path (OstreeSysroot *self);
+
+

Returns

+

Path to rootfs.

+

[transfer none]

+
+
+
+
+

ostree_sysroot_load ()

+
gboolean
+ostree_sysroot_load (OstreeSysroot *self,
+                     GCancellable *cancellable,
+                     GError **error);
+

Load deployment list, bootversion, and subbootversion from the +rootfs self +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Sysroot

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_load_if_changed ()

+
gboolean
+ostree_sysroot_load_if_changed (OstreeSysroot *self,
+                                gboolean *out_changed,
+                                GCancellable *cancellable,
+                                GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

OstreeSysroot

 

out_changed

.

[out caller-allocates]

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2016.4

+
+
+
+

ostree_sysroot_lock ()

+
gboolean
+ostree_sysroot_lock (OstreeSysroot *self,
+                     GError **error);
+

Acquire an exclusive multi-process write lock for self +. This call +blocks until the lock has been acquired. The lock is not +reentrant.

+

Release the lock with ostree_sysroot_unlock(). The lock will also +be released if self + is deallocated.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

Self

 

error

Error

 
+
+
+
+
+

ostree_sysroot_try_lock ()

+
gboolean
+ostree_sysroot_try_lock (OstreeSysroot *self,
+                         gboolean *out_acquired,
+                         GError **error);
+

Try to acquire an exclusive multi-process write lock for self +. If +another process holds the lock, this function will return +immediately, setting out_acquired + to FALSE, and returning TRUE +(and no error).

+

Release the lock with ostree_sysroot_unlock(). The lock will also +be released if self + is deallocated.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Self

 

out_acquired

Whether or not the lock has been acquired.

[out]

error

Error

 
+
+
+
+
+

ostree_sysroot_lock_async ()

+
void
+ostree_sysroot_lock_async (OstreeSysroot *self,
+                           GCancellable *cancellable,
+                           GAsyncReadyCallback callback,
+                           gpointer user_data);
+

An asynchronous version of ostree_sysroot_lock().

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

cancellable

Cancellable

 

callback

Callback

 

user_data

User data

 
+
+
+
+
+

ostree_sysroot_lock_finish ()

+
gboolean
+ostree_sysroot_lock_finish (OstreeSysroot *self,
+                            GAsyncResult *result,
+                            GError **error);
+

Call when ostree_sysroot_lock_async() is ready.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Self

 

result

Result

 

error

Error

 
+
+
+
+
+

ostree_sysroot_unlock ()

+
void
+ostree_sysroot_unlock (OstreeSysroot *self);
+

Clear the lock previously acquired with ostree_sysroot_lock(). It +is safe to call this function if the lock has not been previously +acquired.

+
+

Parameters

+
+++++ + + + + + +

self

Self

 
+
+
+
+
+

ostree_sysroot_unload ()

+
void
+ostree_sysroot_unload (OstreeSysroot *self);
+

Release any resources such as file descriptors referring to the +root directory of this sysroot. Normally, those resources are +cleared by finalization, but in garbage collected languages that +may not be predictable.

+

This undoes the effect of ostree_sysroot_load().

+
+

Parameters

+
+++++ + + + + + +

self

Sysroot

 
+
+
+
+
+

ostree_sysroot_set_mount_namespace_in_use ()

+
void
+ostree_sysroot_set_mount_namespace_in_use
+                               (OstreeSysroot *self);
+

If this function is invoked, then libostree will assume that +a private Linux mount namespace has been created by the process. +The primary use case for this is to have e.g. /sysroot mounted +read-only by default.

+

If this function has been called, then when a function which requires +writable access is invoked, libostree will automatically remount as writable +any mount points on which it operates. This currently is just /sysroot and +/boot.

+

If you invoke this function, it must be before ostree_sysroot_load(); it may +be invoked before or after ostree_sysroot_initialize().

+

Since: 2020.1

+
+
+
+

ostree_sysroot_is_booted ()

+
gboolean
+ostree_sysroot_is_booted (OstreeSysroot *self);
+

Can only be invoked after ostree_sysroot_initialize().

+
+

Parameters

+
+++++ + + + + + +

self

Sysroot

 
+
+
+

Returns

+

TRUE iff the sysroot points to a booted deployment

+
+

Since: 2020.1

+
+
+
+

ostree_sysroot_get_fd ()

+
int
+ostree_sysroot_get_fd (OstreeSysroot *self);
+

Access a file descriptor that refers to the root directory of this sysroot. +ostree_sysroot_initialize() (or ostree_sysroot_load()) must have been invoked +prior to calling this function.

+
+

Parameters

+
+++++ + + + + + +

self

Sysroot

 
+
+
+

Returns

+

A file descriptor valid for the lifetime of self +

+
+
+
+
+

ostree_sysroot_ensure_initialized ()

+
gboolean
+ostree_sysroot_ensure_initialized (OstreeSysroot *self,
+                                   GCancellable *cancellable,
+                                   GError **error);
+

Ensure that self + is set up as a valid rootfs, by creating +/ostree/repo, among other things.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Sysroot

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_get_bootversion ()

+
int
+ostree_sysroot_get_bootversion (OstreeSysroot *self);
+
+
+
+

ostree_sysroot_get_subbootversion ()

+
int
+ostree_sysroot_get_subbootversion (OstreeSysroot *self);
+
+
+
+

ostree_sysroot_get_deployments ()

+
GPtrArray *
+ostree_sysroot_get_deployments (OstreeSysroot *self);
+
+

Parameters

+
+++++ + + + + + +

self

Sysroot

 
+
+
+

Returns

+

Ordered list of deployments.

+

[element-type OstreeDeployment][transfer container]

+
+
+
+
+

ostree_sysroot_get_booted_deployment ()

+
OstreeDeployment *
+ostree_sysroot_get_booted_deployment (OstreeSysroot *self);
+
+

Parameters

+
+++++ + + + + + +

self

Sysroot

 
+
+
+

Returns

+

The currently booted deployment, or NULL if none.

+

[transfer none]

+
+
+
+
+

ostree_sysroot_get_deployment_directory ()

+
GFile *
+ostree_sysroot_get_deployment_directory
+                               (OstreeSysroot *self,
+                                OstreeDeployment *deployment);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

Sysroot

 

deployment

A deployment

 
+
+
+

Returns

+

Path to deployment root directory.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_get_deployment_dirpath ()

+
char *
+ostree_sysroot_get_deployment_dirpath (OstreeSysroot *self,
+                                       OstreeDeployment *deployment);
+

Note this function only returns a *relative* path - if you want +to access, it, you must either use fd-relative api such as openat(), +or concatenate it with the full ostree_sysroot_get_path().

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

Repo

 

deployment

A deployment

 
+
+
+

Returns

+

Path to deployment root directory, relative to sysroot.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_get_deployment_origin_path ()

+
GFile *
+ostree_sysroot_get_deployment_origin_path
+                               (GFile *deployment_path);
+
+

Parameters

+
+++++ + + + + + +

deployment_path

A deployment path

 
+
+
+

Returns

+

Path to deployment origin file.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_cleanup ()

+
gboolean
+ostree_sysroot_cleanup (OstreeSysroot *self,
+                        GCancellable *cancellable,
+                        GError **error);
+

Delete any state that resulted from a partially completed +transaction, such as incomplete deployments.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Sysroot

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_prepare_cleanup ()

+
gboolean
+ostree_sysroot_prepare_cleanup (OstreeSysroot *self,
+                                GCancellable *cancellable,
+                                GError **error);
+

Like ostree_sysroot_cleanup() in that it cleans up incomplete deployments +and old boot versions, but does NOT prune the repository.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Sysroot

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_cleanup_prune_repo ()

+
gboolean
+ostree_sysroot_cleanup_prune_repo (OstreeSysroot *sysroot,
+                                   OstreeRepoPruneOptions *options,
+                                   gint *out_objects_total,
+                                   gint *out_objects_pruned,
+                                   guint64 *out_pruned_object_size_total,
+                                   GCancellable *cancellable,
+                                   GError **error);
+

Prune the system repository. This is a thin wrapper +around ostree_repo_prune_from_reachable(); the primary +addition is that this function automatically gathers +all deployed commits into the reachable set.

+

You generally want to at least set the OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY +flag in options +. A commit traversal depth of 0 is assumed.

+

Locking: exclusive

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

sysroot

Sysroot

 

options

Flags controlling pruning

 

out_objects_total

Number of objects found.

[out]

out_objects_pruned

Number of objects deleted.

[out]

out_pruned_object_size_total

Storage size in bytes of objects deleted.

[out]

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2018.6

+
+
+
+

ostree_sysroot_repo ()

+
OstreeRepo *
+ostree_sysroot_repo (OstreeSysroot *self);
+

This function is a variant of ostree_sysroot_get_repo() that cannot fail, and +returns a cached repository. Can only be called after ostree_sysroot_initialize() +or ostree_sysroot_load() has been invoked successfully.

+
+

Parameters

+
+++++ + + + + + +

self

Sysroot

 
+
+
+

Returns

+

The OSTree repository in sysroot self +.

+

[transfer none]

+
+

Since: 2017.7

+
+
+
+

ostree_sysroot_get_repo ()

+
gboolean
+ostree_sysroot_get_repo (OstreeSysroot *self,
+                         OstreeRepo **out_repo,
+                         GCancellable *cancellable,
+                         GError **error);
+

Retrieve the OSTree repository in sysroot self +. The repo is guaranteed to be open +(see ostree_repo_open()).

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

out_repo

Repository in sysroot self +.

[out][transfer full][optional]

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

TRUE on success, FALSE otherwise

+
+
+
+
+

ostree_sysroot_get_staged_deployment ()

+
OstreeDeployment *
+ostree_sysroot_get_staged_deployment (OstreeSysroot *self);
+
+

Parameters

+
+++++ + + + + + +

self

Sysroot

 
+
+
+

Returns

+

The currently staged deployment, or NULL if none.

+

[transfer none]

+
+

Since: 2018.5

+
+
+
+

ostree_sysroot_init_osname ()

+
gboolean
+ostree_sysroot_init_osname (OstreeSysroot *self,
+                            const char *osname,
+                            GCancellable *cancellable,
+                            GError **error);
+

Initialize the directory structure for an "osname", which is a +group of operating system deployments, with a shared /var. One +is required for generating a deployment.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

osname

Name group of operating system checkouts

 

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2016.4

+
+
+
+

ostree_sysroot_deployment_set_kargs ()

+
gboolean
+ostree_sysroot_deployment_set_kargs (OstreeSysroot *self,
+                                     OstreeDeployment *deployment,
+                                     char **new_kargs,
+                                     GCancellable *cancellable,
+                                     GError **error);
+

Entirely replace the kernel arguments of deployment + with the +values in new_kargs +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

deployment

A deployment

 

new_kargs

Replace deployment's kernel arguments.

[array zero-terminated=1][element-type utf8]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_deployment_set_mutable ()

+
gboolean
+ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
+                                       OstreeDeployment *deployment,
+                                       gboolean is_mutable,
+                                       GCancellable *cancellable,
+                                       GError **error);
+

By default, deployment directories are not mutable. This function +will allow making them temporarily mutable, for example to allow +layering additional non-OSTree content.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

deployment

A deployment

 

is_mutable

Whether or not deployment's files can be changed

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_deployment_unlock ()

+
gboolean
+ostree_sysroot_deployment_unlock (OstreeSysroot *self,
+                                  OstreeDeployment *deployment,
+                                  OstreeDeploymentUnlockedState unlocked_state,
+                                  GCancellable *cancellable,
+                                  GError **error);
+

Configure the target deployment deployment + such that it +is writable. There are multiple modes, essentially differing +in whether or not any changes persist across reboot.

+

The OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX state is persistent +across reboots.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

deployment

Deployment

 

unlocked_state

Transition to this unlocked state

 

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2016.4

+
+
+
+

ostree_sysroot_deployment_set_pinned ()

+
gboolean
+ostree_sysroot_deployment_set_pinned (OstreeSysroot *self,
+                                      OstreeDeployment *deployment,
+                                      gboolean is_pinned,
+                                      GError **error);
+

By default, deployments may be subject to garbage collection. Typical uses of +libostree only retain at most 2 deployments. If is_pinned + is TRUE, a +metadata bit will be set causing libostree to avoid automatic GC of the +deployment. However, this is really an "advisory" note; it's still possible +for e.g. older versions of libostree unaware of pinning to GC the deployment.

+

This function does nothing and returns successfully if the deployment +is already in the desired pinning state. It is an error to try to pin +the staged deployment (as it's not in the bootloader entries).

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

deployment

A deployment

 

is_pinned

Whether or not deployment will be automatically GC'd

 

error

Error

 
+
+

Since: 2018.3

+
+
+
+

ostree_sysroot_write_deployments ()

+
gboolean
+ostree_sysroot_write_deployments (OstreeSysroot *self,
+                                  GPtrArray *new_deployments,
+                                  GCancellable *cancellable,
+                                  GError **error);
+

Older version of ostree_sysroot_write_deployments_with_options(). This +version will perform post-deployment cleanup by default.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

new_deployments

List of new deployments.

[element-type OstreeDeployment]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_write_deployments_with_options ()

+
gboolean
+ostree_sysroot_write_deployments_with_options
+                               (OstreeSysroot *self,
+                                GPtrArray *new_deployments,
+                                OstreeSysrootWriteDeploymentsOpts *opts,
+                                GCancellable *cancellable,
+                                GError **error);
+

Assuming new_deployments + have already been deployed in place on disk via +ostree_sysroot_deploy_tree(), atomically update bootloader configuration. By +default, no post-transaction cleanup will be performed. You should invoke +ostree_sysroot_cleanup() at some point after the transaction, or specify +do_postclean in opts +. Skipping the post-transaction cleanup is useful +if for example you want to control pruning of the repository.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

new_deployments

List of new deployments.

[element-type OstreeDeployment]

opts

Options

 

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2017.4

+
+
+
+

ostree_sysroot_write_origin_file ()

+
gboolean
+ostree_sysroot_write_origin_file (OstreeSysroot *sysroot,
+                                  OstreeDeployment *deployment,
+                                  GKeyFile *new_origin,
+                                  GCancellable *cancellable,
+                                  GError **error);
+

Immediately replace the origin file of the referenced deployment + +with the contents of new_origin +. If new_origin + is NULL, +this function will write the current origin of deployment +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

sysroot

System root

 

deployment

Deployment

 

new_origin

Origin content.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_stage_tree ()

+
gboolean
+ostree_sysroot_stage_tree (OstreeSysroot *self,
+                           const char *osname,
+                           const char *revision,
+                           GKeyFile *origin,
+                           OstreeDeployment *merge_deployment,
+                           char **override_kernel_argv,
+                           OstreeDeployment **out_new_deployment,
+                           GCancellable *cancellable,
+                           GError **error);
+

Like ostree_sysroot_deploy_tree(), but "finalization" only occurs at OS +shutdown time.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

osname

osname to use for merge deployment.

[allow-none]

revision

Checksum to add

 

origin

Origin to use for upgrades.

[allow-none]

merge_deployment

Use this deployment for merge path.

[allow-none]

override_kernel_argv

Use these as kernel arguments; if NULL, inherit options from provided_merge_deployment.

[allow-none][array zero-terminated=1][element-type utf8]

out_new_deployment

The new deployment path.

[out]

cancellable

Cancellable

 

error

Error

 
+
+

Since: 2018.5

+
+
+
+

ostree_sysroot_deploy_tree ()

+
gboolean
+ostree_sysroot_deploy_tree (OstreeSysroot *self,
+                            const char *osname,
+                            const char *revision,
+                            GKeyFile *origin,
+                            OstreeDeployment *provided_merge_deployment,
+                            char **override_kernel_argv,
+                            OstreeDeployment **out_new_deployment,
+                            GCancellable *cancellable,
+                            GError **error);
+

Check out deployment tree with revision revision +, performing a 3 +way merge with provided_merge_deployment + for configuration.

+

While this API is not deprecated, you most likely want to use the +ostree_sysroot_stage_tree() API.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

osname

osname to use for merge deployment.

[allow-none]

revision

Checksum to add

 

origin

Origin to use for upgrades.

[allow-none]

provided_merge_deployment

Use this deployment for merge path.

[allow-none]

override_kernel_argv

Use these as kernel arguments; if NULL, inherit options from provided_merge_deployment.

[allow-none][array zero-terminated=1][element-type utf8]

out_new_deployment

The new deployment path.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_get_merge_deployment ()

+
OstreeDeployment *
+ostree_sysroot_get_merge_deployment (OstreeSysroot *self,
+                                     const char *osname);
+

Find the deployment to use as a configuration merge source; this is +the first one in the current deployment list which matches osname.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

Sysroot

 

osname

Operating system group.

[allow-none]
+
+
+

Returns

+

Configuration merge deployment.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_query_deployments_for ()

+
void
+ostree_sysroot_query_deployments_for (OstreeSysroot *self,
+                                      const char *osname,
+                                      OstreeDeployment **out_pending,
+                                      OstreeDeployment **out_rollback);
+

Find the pending and rollback deployments for osname +. Pass NULL for osname + +to use the booted deployment's osname. By default, pending deployment is the +first deployment in the order that matches osname +, and rollback + will be the +next one after the booted deployment, or the deployment after the pending if +we're not looking at the booted deployment.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

osname

"stateroot" name.

[allow-none]

out_pending

The pending deployment.

[out][allow-none][transfer full]

out_rollback

The rollback deployment.

[out][allow-none][transfer full]
+
+

Since: 2017.7

+
+
+
+

ostree_sysroot_origin_new_from_refspec ()

+
GKeyFile *
+ostree_sysroot_origin_new_from_refspec
+                               (OstreeSysroot *self,
+                                const char *refspec);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

Sysroot

 

refspec

A refspec

 
+
+
+

Returns

+

A new config file which sets refspec +as an origin.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_simple_write_deployment ()

+
gboolean
+ostree_sysroot_simple_write_deployment
+                               (OstreeSysroot *sysroot,
+                                const char *osname,
+                                OstreeDeployment *new_deployment,
+                                OstreeDeployment *merge_deployment,
+                                OstreeSysrootSimpleWriteDeploymentFlags flags,
+                                GCancellable *cancellable,
+                                GError **error);
+

Prepend new_deployment + to the list of deployments, commit, and +cleanup. By default, all other deployments for the given osname + +except the merge deployment and the booted deployment will be +garbage collected.

+

If OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN is +specified, then all current deployments will be kept.

+

If OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING is +specified, then pending deployments will be kept.

+

If OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK is +specified, then rollback deployments will be kept.

+

If OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT is +specified, then instead of prepending, the new deployment will be +added right after the booted or merge deployment, instead of first.

+

If OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN is +specified, then no cleanup will be performed after adding the +deployment. Make sure to call ostree_sysroot_cleanup() sometime +later, instead.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

sysroot

Sysroot

 

osname

OS name.

[allow-none]

new_deployment

Prepend this deployment to the list

 

merge_deployment

Use this deployment for configuration merge.

[allow-none]

flags

Flags controlling behavior

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

Types and Values

+
+

OstreeSysroot

+
typedef struct OstreeSysroot OstreeSysroot;
+
+
+
+
+

enum OstreeSysrootSimpleWriteDeploymentFlags

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NONE

  

OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN

  

OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT

  

OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN

  

OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING

  

OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK

  
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-SELinux-policy-management.html b/apidoc/html/ostree-SELinux-policy-management.html new file mode 100644 index 0000000..1fa9eae --- /dev/null +++ b/apidoc/html/ostree-SELinux-policy-management.html @@ -0,0 +1,491 @@ + + + + +SELinux policy management: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

SELinux policy management

+

SELinux policy management — Read SELinux policy and manage filesystem labels

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+OstreeSePolicy * + +ostree_sepolicy_new () +
+OstreeSePolicy * + +ostree_sepolicy_new_at () +
+GFile * + +ostree_sepolicy_get_path () +
const char * + +ostree_sepolicy_get_name () +
+gboolean + +ostree_sepolicy_get_label () +
const char * + +ostree_sepolicy_get_csum () +
+gboolean + +ostree_sepolicy_restorecon () +
+gboolean + +ostree_sepolicy_setfscreatecon () +
+void + +ostree_sepolicy_fscreatecon_cleanup () +
+
+
+

Types and Values

+
++++ + + + + + + + + + + +
typedefOstreeSePolicy
enumOstreeSePolicyRestoreconFlags
+
+
+

Description

+

A OstreeSePolicy object can load the SELinux policy from a given +root and perform labeling.

+
+
+

Functions

+
+

ostree_sepolicy_new ()

+
OstreeSePolicy *
+ostree_sepolicy_new (GFile *path,
+                     GCancellable *cancellable,
+                     GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

path

Path to a root directory

 

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

An accessor object for SELinux policy in root located at path +.

+

[transfer full]

+
+
+
+
+

ostree_sepolicy_new_at ()

+
OstreeSePolicy *
+ostree_sepolicy_new_at (int rootfs_dfd,
+                        GCancellable *cancellable,
+                        GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

rootfs_dfd

Directory fd for rootfs (will not be cloned)

 

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

An accessor object for SELinux policy in root located at rootfs_dfd +.

+

[transfer full]

+
+

Since: 2017.4

+
+
+
+

ostree_sepolicy_get_path ()

+
GFile *
+ostree_sepolicy_get_path (OstreeSePolicy *self);
+
+

Returns

+

Path to rootfs.

+

[transfer none]

+
+
+
+
+

ostree_sepolicy_get_name ()

+
const char *
+ostree_sepolicy_get_name (OstreeSePolicy *self);
+
+

Returns

+

Type of current policy.

+

[transfer none]

+
+
+
+
+

ostree_sepolicy_get_label ()

+
gboolean
+ostree_sepolicy_get_label (OstreeSePolicy *self,
+                           const char *relpath,
+                           guint32 unix_mode,
+                           char **out_label,
+                           GCancellable *cancellable,
+                           GError **error);
+

Store in out_label + the security context for the given relpath + and +mode unix_mode +. If the policy does not specify a label, NULL +will be returned.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

relpath

Path

 

unix_mode

Unix mode

 

out_label

Return location for security context.

[allow-none][out][transfer full]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sepolicy_get_csum ()

+
const char *
+ostree_sepolicy_get_csum (OstreeSePolicy *self);
+
+

Returns

+

Checksum of current policy.

+

[transfer none]

+
+

Since: 2016.5

+
+
+
+

ostree_sepolicy_restorecon ()

+
gboolean
+ostree_sepolicy_restorecon (OstreeSePolicy *self,
+                            const char *path,
+                            GFileInfo *info,
+                            GFile *target,
+                            OstreeSePolicyRestoreconFlags flags,
+                            char **out_new_label,
+                            GCancellable *cancellable,
+                            GError **error);
+

Reset the security context of target + based on the SELinux policy.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

path

Path string to use for policy lookup

 

info

File attributes.

[allow-none]

target

Physical path to target file

 

flags

Flags controlling behavior

 

out_new_label

New label, or NULL if unchanged.

[allow-none][out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sepolicy_setfscreatecon ()

+
gboolean
+ostree_sepolicy_setfscreatecon (OstreeSePolicy *self,
+                                const char *path,
+                                guint32 mode,
+                                GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Policy

 

path

Use this path to determine a label

 

mode

Used along with path +

 

error

Error

 
+
+
+
+
+

ostree_sepolicy_fscreatecon_cleanup ()

+
void
+ostree_sepolicy_fscreatecon_cleanup (void **unused);
+

Cleanup function for ostree_sepolicy_setfscreatecon().

+
+

Parameters

+
+++++ + + + + + +

unused

Not used, just in case you didn't infer that from the parameter name

 
+
+
+
+
+

Types and Values

+
+

OstreeSePolicy

+
typedef struct OstreeSePolicy OstreeSePolicy;
+
+
+
+
+

enum OstreeSePolicyRestoreconFlags

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + +

OSTREE_SEPOLICY_RESTORECON_FLAGS_NONE

  

OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL

  

OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING

  
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-Signature-management.html b/apidoc/html/ostree-Signature-management.html new file mode 100644 index 0000000..dcd6075 --- /dev/null +++ b/apidoc/html/ostree-Signature-management.html @@ -0,0 +1,865 @@ + + + + +Signature management: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

Signature management

+

Signature management — Sign and verify commits

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+GPtrArray * + +ostree_sign_get_all () +
+gboolean + +ostree_sign_commit () +
+gboolean + +ostree_sign_commit_verify () +
+gboolean + +ostree_sign_data () +
+gboolean + +ostree_sign_data_verify () +
+OstreeSign * + +ostree_sign_get_by_name () +
const gchar * + +ostree_sign_get_name () +
+gboolean + +ostree_sign_add_pk () +
+gboolean + +ostree_sign_clear_keys () +
+gboolean + +ostree_sign_load_pk () +
const gchar * + +ostree_sign_metadata_format () +
const gchar * + +ostree_sign_metadata_key () +
+gboolean + +ostree_sign_set_pk () +
+gboolean + +ostree_sign_set_sk () +
+gboolean + +ostree_sign_summary () +
+
+
+

Types and Values

+
++++ + + + + +
 OstreeSign
+
+
+

Description

+

An OstreeSign interface allows to select and use any available engine +for signing or verifying the commit object or summary file.

+
+
+

Functions

+
+

ostree_sign_get_all ()

+
GPtrArray *
+ostree_sign_get_all (void);
+

Return an array with newly allocated instances of all available +signing engines; they will not be initialized.

+
+

Returns

+

an array of signing engines.

+

[transfer full][element-type OstreeSign]

+
+

Since: 2020.2

+
+
+
+

ostree_sign_commit ()

+
gboolean
+ostree_sign_commit (OstreeSign *self,
+                    OstreeRepo *repo,
+                    const gchar *commit_checksum,
+                    GCancellable *cancellable,
+                    GError **error);
+

Add a signature to a commit.

+

Depending of the signing engine used you will need to load +the secret key with ostree_sign_set_sk.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

an OstreeSign object

 

repo

an OsreeRepo object

 

commit_checksum

SHA256 of given commit to sign

 

cancellable

A GCancellable

 

error

a GError

 
+
+
+

Returns

+

TRUE +if commit has been signed successfully, +FALSE +in case of error (error +will contain the reason).

+
+

Since: 2020.2

+
+
+
+

ostree_sign_commit_verify ()

+
gboolean
+ostree_sign_commit_verify (OstreeSign *self,
+                           OstreeRepo *repo,
+                           const gchar *commit_checksum,
+                           char **out_success_message,
+                           GCancellable *cancellable,
+                           GError **error);
+

Verify if commit is signed with known key.

+

Depending of the signing engine used you will need to load +the public key(s) for verification with ostree_sign_set_pk, +ostree_sign_add_pk and/or ostree_sign_load_pk.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

an OstreeSign object

 

repo

an OsreeRepo object

 

commit_checksum

SHA256 of given commit to verify

 

cancellable

A GCancellable

 

error

a GError

 
+
+
+

Returns

+

TRUE +if commit has been verified successfully, +FALSE +in case of error or no valid keys are available (error +will contain the reason).

+
+

Since: 2020.2

+
+
+
+

ostree_sign_data ()

+
gboolean
+ostree_sign_data (OstreeSign *self,
+                  GBytes *data,
+                  GBytes **signature,
+                  GCancellable *cancellable,
+                  GError **error);
+

Sign the given data + with pre-loaded secret key.

+

Depending of the signing engine used you will need to load +the secret key with ostree_sign_set_sk.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

an OstreeSign object

 

data

the raw data to be signed with pre-loaded secret key

 

signature

in case of success will contain signature

 

cancellable

A GCancellable

 

error

a GError

 
+
+
+

Returns

+

TRUE +if data +has been signed successfully, +FALSE +in case of error (error +will contain the reason).

+
+

Since: 2020.2

+
+
+
+

ostree_sign_data_verify ()

+
gboolean
+ostree_sign_data_verify (OstreeSign *self,
+                         GBytes *data,
+                         GVariant *signatures,
+                         char **out_success_message,
+                         GError **error);
+

Verify given data against signatures with pre-loaded public keys.

+

Depending of the signing engine used you will need to load +the public key(s) with ostree_sign_set_pk, ostree_sign_add_pk +or ostree_sign_load_pk.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

an OstreeSign object

 

data

the raw data to check

 

signatures

the signatures to be checked

 

error

a GError

 
+
+
+

Returns

+

TRUE +if data +has been signed at least with any single valid key, +FALSE +in case of error or no valid keys are available (error +will contain the reason).

+
+

Since: 2020.2

+
+
+
+

ostree_sign_get_by_name ()

+
OstreeSign *
+ostree_sign_get_by_name (const gchar *name,
+                         GError **error);
+

Create a new instance of a signing engine.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

name

the name of desired signature engine

 

error

return location for a GError

 
+
+
+

Returns

+

New signing engine, or NULL if the engine is not known.

+

[transfer full]

+
+

Since: 2020.2

+
+
+
+

ostree_sign_get_name ()

+
const gchar *
+ostree_sign_get_name (OstreeSign *self);
+

Return the pointer to the name of currently used/selected signing engine.

+
+

Parameters

+
+++++ + + + + + +

self

an OstreeSign object

 
+
+
+

Returns

+

pointer to the name +NULL +in case of error (unlikely).

+

[transfer none]

+
+

Since: 2020.2

+
+
+
+

ostree_sign_add_pk ()

+
gboolean
+ostree_sign_add_pk (OstreeSign *self,
+                    GVariant *public_key,
+                    GError **error);
+

Add the public key for verification. Could be called multiple times for +adding all needed keys to be used for verification.

+

The public_key + argument depends of the particular engine implementation.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

an OstreeSign object

 

public_key

single public key to be added

 

error

a GError

 
+
+
+

Returns

+

TRUE +in case if the key could be added successfully, +FALSE +in case of error (error +will contain the reason).

+
+

Since: 2020.2

+
+
+
+

ostree_sign_clear_keys ()

+
gboolean
+ostree_sign_clear_keys (OstreeSign *self,
+                        GError **error);
+

Clear all previously preloaded secret and public keys.

+
+

Parameters

+
+++++ + + + + + + + + + + + + +

self

an OstreeSign object

 

error

a GError

 
+
+
+

Returns

+

TRUE +in case if no errors, FALSE +in case of error

+
+

Since: 2020.2

+
+
+
+

ostree_sign_load_pk ()

+
gboolean
+ostree_sign_load_pk (OstreeSign *self,
+                     GVariant *options,
+                     GError **error);
+

Load public keys for verification from anywhere. +It is expected that all keys would be added to already pre-loaded keys.

+

The options + argument depends of the particular engine implementation.

+

For example, ed25515 + engine could use following string-formatted options:

+
    +
  • filename + -- single file to use to load keys from

  • +
  • basedir + -- directory containing subdirectories +'trusted.ed25519.d' and 'revoked.ed25519.d' with appropriate +public keys. Used for testing and re-definition of system-wide +directories if defaults are not suitable for any reason.

  • +
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

an OstreeSign object

 

options

any options

 

error

a GError

 
+
+
+

Returns

+

TRUE +in case if at least one key could be load successfully, +FALSE +in case of error (error +will contain the reason).

+
+

Since: 2020.2

+
+
+
+

ostree_sign_metadata_format ()

+
const gchar *
+ostree_sign_metadata_format (OstreeSign *self);
+

Return the pointer to the string with format used in (detached) metadata for +current signing engine.

+
+

Parameters

+
+++++ + + + + + +

self

an OstreeSign object

 
+
+
+

Returns

+

pointer to the metadata format, +NULL +in case of error (unlikely).

+

[transfer none]

+
+

Since: 2020.2

+
+
+
+

ostree_sign_metadata_key ()

+
const gchar *
+ostree_sign_metadata_key (OstreeSign *self);
+

Return the pointer to the name of the key used in (detached) metadata for +current signing engine.

+
+

Parameters

+
+++++ + + + + + +

self

an OstreeSign object

 
+
+
+

Returns

+

pointer to the metadata key name, +NULL +in case of error (unlikely).

+

[transfer none]

+
+

Since: 2020.2

+
+
+
+

ostree_sign_set_pk ()

+
gboolean
+ostree_sign_set_pk (OstreeSign *self,
+                    GVariant *public_key,
+                    GError **error);
+

Set the public key for verification. It is expected what all +previously pre-loaded public keys will be dropped.

+

The public_key + argument depends of the particular engine implementation.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

an OstreeSign object

 

public_key

single public key to be added

 

error

a GError

 
+
+
+

Returns

+

TRUE +in case if the key could be set successfully, +FALSE +in case of error (error +will contain the reason).

+
+

Since: 2020.2

+
+
+
+

ostree_sign_set_sk ()

+
gboolean
+ostree_sign_set_sk (OstreeSign *self,
+                    GVariant *secret_key,
+                    GError **error);
+

Set the secret key to be used for signing data, commits and summary.

+

The secret_key + argument depends of the particular engine implementation.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

an OstreeSign object

 

secret_key

secret key to be added

 

error

a GError

 
+
+
+

Returns

+

TRUE +in case if the key could be set successfully, +FALSE +in case of error (error +will contain the reason).

+
+

Since: 2020.2

+
+
+
+

ostree_sign_summary ()

+
gboolean
+ostree_sign_summary (OstreeSign *self,
+                     OstreeRepo *repo,
+                     GVariant *keys,
+                     GCancellable *cancellable,
+                     GError **error);
+

Add a signature to a summary file. +Based on ostree_repo_add_gpg_signature_summary implementation.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Self

 

repo

ostree repository

 

keys

keys -- GVariant containing keys as GVarints specific to signature type.

 

cancellable

A GCancellable

 

error

a GError

 
+
+
+

Returns

+

TRUE +if summary file has been signed with all provided keys

+
+
+
+
+

Types and Values

+
+

OstreeSign

+
typedef struct _OstreeSign OstreeSign;
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-Simple-upgrade-class.html b/apidoc/html/ostree-Simple-upgrade-class.html new file mode 100644 index 0000000..3fb9312 --- /dev/null +++ b/apidoc/html/ostree-Simple-upgrade-class.html @@ -0,0 +1,715 @@ + + + + +Simple upgrade class: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

Simple upgrade class

+

Simple upgrade class — Upgrade OSTree systems

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+OstreeSysrootUpgrader * + +ostree_sysroot_upgrader_new () +
+OstreeSysrootUpgrader * + +ostree_sysroot_upgrader_new_for_os () +
+OstreeSysrootUpgrader * + +ostree_sysroot_upgrader_new_for_os_with_flags () +
+GKeyFile * + +ostree_sysroot_upgrader_get_origin () +
+GKeyFile * + +ostree_sysroot_upgrader_dup_origin () +
+gboolean + +ostree_sysroot_upgrader_set_origin () +
+char * + +ostree_sysroot_upgrader_get_origin_description () +
+gboolean + +ostree_sysroot_upgrader_check_timestamps () +
+gboolean + +ostree_sysroot_upgrader_pull () +
+gboolean + +ostree_sysroot_upgrader_pull_one_dir () +
+gboolean + +ostree_sysroot_upgrader_deploy () +
+
+
+

Types and Values

+ +
+
+

Description

+

The OstreeSysrootUpgrader class allows performing simple upgrade +operations.

+
+
+

Functions

+
+

ostree_sysroot_upgrader_new ()

+
OstreeSysrootUpgrader *
+ostree_sysroot_upgrader_new (OstreeSysroot *sysroot,
+                             GCancellable *cancellable,
+                             GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

sysroot

An OstreeSysroot

 

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

An upgrader.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_upgrader_new_for_os ()

+
OstreeSysrootUpgrader *
+ostree_sysroot_upgrader_new_for_os (OstreeSysroot *sysroot,
+                                    const char *osname,
+                                    GCancellable *cancellable,
+                                    GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

sysroot

An OstreeSysroot

 

osname

Operating system name.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

An upgrader.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_upgrader_new_for_os_with_flags ()

+
OstreeSysrootUpgrader *
+ostree_sysroot_upgrader_new_for_os_with_flags
+                               (OstreeSysroot *sysroot,
+                                const char *osname,
+                                OstreeSysrootUpgraderFlags flags,
+                                GCancellable *cancellable,
+                                GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

sysroot

An OstreeSysroot

 

osname

Operating system name.

[allow-none]

flags

Flags

 

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

An upgrader.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_upgrader_get_origin ()

+
GKeyFile *
+ostree_sysroot_upgrader_get_origin (OstreeSysrootUpgrader *self);
+
+

Parameters

+
+++++ + + + + + +

self

Sysroot

 
+
+
+

Returns

+

The origin file, or NULL if unknown.

+

[transfer none]

+
+
+
+
+

ostree_sysroot_upgrader_dup_origin ()

+
GKeyFile *
+ostree_sysroot_upgrader_dup_origin (OstreeSysrootUpgrader *self);
+
+

Parameters

+
+++++ + + + + + +

self

Sysroot

 
+
+
+

Returns

+

A copy of the origin file, or NULL if unknown.

+

[transfer full]

+
+
+
+
+

ostree_sysroot_upgrader_set_origin ()

+
gboolean
+ostree_sysroot_upgrader_set_origin (OstreeSysrootUpgrader *self,
+                                    GKeyFile *origin,
+                                    GCancellable *cancellable,
+                                    GError **error);
+

Replace the origin with origin +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

Sysroot

 

origin

The new origin.

[allow-none]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_upgrader_get_origin_description ()

+
char *
+ostree_sysroot_upgrader_get_origin_description
+                               (OstreeSysrootUpgrader *self);
+
+

Parameters

+
+++++ + + + + + +

self

Upgrader

 
+
+
+

Returns

+

A one-line descriptive summary of the origin, or NULL if unknown

+
+
+
+
+

ostree_sysroot_upgrader_check_timestamps ()

+
gboolean
+ostree_sysroot_upgrader_check_timestamps
+                               (OstreeRepo *repo,
+                                const char *from_rev,
+                                const char *to_rev,
+                                GError **error);
+

Check that the timestamp on to_rev + is equal to or newer than +from_rev +. This protects systems against man-in-the-middle +attackers which provide a client with an older commit.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

repo

Repo

 

from_rev

From revision

 

to_rev

To revision

 

error

Error

 
+
+
+
+
+

ostree_sysroot_upgrader_pull ()

+
gboolean
+ostree_sysroot_upgrader_pull (OstreeSysrootUpgrader *self,
+                              OstreeRepoPullFlags flags,
+                              OstreeSysrootUpgraderPullFlags upgrader_flags,
+                              OstreeAsyncProgress *progress,
+                              gboolean *out_changed,
+                              GCancellable *cancellable,
+                              GError **error);
+

Perform a pull from the origin. First check if the ref has +changed, if so download the linked objects, and store the updated +ref locally. Then out_changed + will be TRUE.

+

If the origin remote is unchanged, out_changed + will be set to +FALSE.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Upgrader

 

flags

Flags controlling pull behavior

 

upgrader_flags

Flags controlling upgrader behavior

 

progress

Progress.

[allow-none]

out_changed

Whether or not the origin changed.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_upgrader_pull_one_dir ()

+
gboolean
+ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
+                                      const char *dir_to_pull,
+                                      OstreeRepoPullFlags flags,
+                                      OstreeSysrootUpgraderPullFlags upgrader_flags,
+                                      OstreeAsyncProgress *progress,
+                                      gboolean *out_changed,
+                                      GCancellable *cancellable,
+                                      GError **error);
+

Like ostree_sysroot_upgrader_pull(), but allows retrieving just a +subpath of the tree. This can be used to download metadata files +from inside the tree such as package databases.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Upgrader

 

dir_to_pull

Subdirectory path (should include a leading /)

 

flags

Flags controlling pull behavior

 

upgrader_flags

Flags controlling upgrader behavior

 

progress

Progress.

[allow-none]

out_changed

Whether or not the origin changed.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_sysroot_upgrader_deploy ()

+
gboolean
+ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self,
+                                GCancellable *cancellable,
+                                GError **error);
+

Write the new deployment to disk, perform a configuration merge +with /etc, and update the bootloader configuration.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + +

self

Self

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

Types and Values

+
+

OstreeSysrootUpgrader

+
typedef struct OstreeSysrootUpgrader OstreeSysrootUpgrader;
+
+
+
+
+

enum OstreeSysrootUpgraderFlags

+

Flags controlling operation of an OstreeSysrootUpgrader.

+
+

Members

+
+++++ + + + + + + + + + + + + +

OSTREE_SYSROOT_UPGRADER_FLAGS_NONE

+

No options

+
 

OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED

+

Do not error if the origin has an unconfigured-state key

+
 
+
+
+
+
+

enum OstreeSysrootUpgraderPullFlags

+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + +

OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_NONE

  

OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER

  

OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC

  
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-bootconfig-parser.html b/apidoc/html/ostree-ostree-bootconfig-parser.html new file mode 100644 index 0000000..c9fdc37 --- /dev/null +++ b/apidoc/html/ostree-ostree-bootconfig-parser.html @@ -0,0 +1,261 @@ + + + + +ostree-bootconfig-parser: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

ostree-bootconfig-parser

+

ostree-bootconfig-parser

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+OstreeBootconfigParser * + +ostree_bootconfig_parser_new () +
+OstreeBootconfigParser * + +ostree_bootconfig_parser_clone () +
+gboolean + +ostree_bootconfig_parser_parse () +
+gboolean + +ostree_bootconfig_parser_parse_at () +
+gboolean + +ostree_bootconfig_parser_write () +
+gboolean + +ostree_bootconfig_parser_write_at () +
+void + +ostree_bootconfig_parser_set () +
const char * + +ostree_bootconfig_parser_get () +
+
+
+

Types and Values

+
++++ + + + + +
 OstreeBootconfigParser
+
+
+

Description

+
+
+

Functions

+
+

ostree_bootconfig_parser_new ()

+
OstreeBootconfigParser *
+ostree_bootconfig_parser_new (void);
+
+
+
+

ostree_bootconfig_parser_clone ()

+
OstreeBootconfigParser *
+ostree_bootconfig_parser_clone (OstreeBootconfigParser *self);
+
+

Parameters

+
+++++ + + + + + +

self

Bootconfig to clone

 
+
+
+

Returns

+

Copy of self +.

+

[transfer full]

+
+
+
+
+

ostree_bootconfig_parser_parse ()

+
gboolean
+ostree_bootconfig_parser_parse (OstreeBootconfigParser *self,
+                                GFile *path,
+                                GCancellable *cancellable,
+                                GError **error);
+
+
+
+

ostree_bootconfig_parser_parse_at ()

+
gboolean
+ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
+                                   int dfd,
+                                   const char *path,
+                                   GCancellable *cancellable,
+                                   GError **error);
+

Initialize a bootconfig from the given file.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Parser

 

dfd

Directory fd

 

path

File path

 

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_bootconfig_parser_write ()

+
gboolean
+ostree_bootconfig_parser_write (OstreeBootconfigParser *self,
+                                GFile *output,
+                                GCancellable *cancellable,
+                                GError **error);
+
+
+
+

ostree_bootconfig_parser_write_at ()

+
gboolean
+ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self,
+                                   int dfd,
+                                   const char *path,
+                                   GCancellable *cancellable,
+                                   GError **error);
+
+
+
+

ostree_bootconfig_parser_set ()

+
void
+ostree_bootconfig_parser_set (OstreeBootconfigParser *self,
+                              const char *key,
+                              const char *value);
+
+
+
+

ostree_bootconfig_parser_get ()

+
const char *
+ostree_bootconfig_parser_get (OstreeBootconfigParser *self,
+                              const char *key);
+
+
+
+

Types and Values

+
+

OstreeBootconfigParser

+
typedef struct _OstreeBootconfigParser OstreeBootconfigParser;
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-chain-input-stream.html b/apidoc/html/ostree-ostree-chain-input-stream.html new file mode 100644 index 0000000..472cfb1 --- /dev/null +++ b/apidoc/html/ostree-ostree-chain-input-stream.html @@ -0,0 +1,89 @@ + + + + +ostree-chain-input-stream: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

ostree-chain-input-stream

+

ostree-chain-input-stream

+
+
+

Functions

+ +
+
+

Types and Values

+
++++ + + + + +
structOstreeChainInputStream
+
+
+

Description

+
+
+

Functions

+
+

ostree_chain_input_stream_new ()

+
OstreeChainInputStream *
+ostree_chain_input_stream_new (GPtrArray *streams);
+
+
+
+

Types and Values

+
+

struct OstreeChainInputStream

+
struct OstreeChainInputStream {
+  GInputStream parent_instance;
+};
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-checksum-input-stream.html b/apidoc/html/ostree-ostree-checksum-input-stream.html new file mode 100644 index 0000000..df11c0e --- /dev/null +++ b/apidoc/html/ostree-ostree-checksum-input-stream.html @@ -0,0 +1,90 @@ + + + + +ostree-checksum-input-stream: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

ostree-checksum-input-stream

+

ostree-checksum-input-stream

+
+
+

Functions

+ +
+
+

Types and Values

+
++++ + + + + +
structOstreeChecksumInputStream
+
+
+

Description

+
+
+

Functions

+
+

ostree_checksum_input_stream_new ()

+
OstreeChecksumInputStream *
+ostree_checksum_input_stream_new (GInputStream *stream,
+                                  GChecksum *checksum);
+
+
+
+

Types and Values

+
+

struct OstreeChecksumInputStream

+
struct OstreeChecksumInputStream {
+  GFilterInputStream parent_instance;
+};
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-deployment.html b/apidoc/html/ostree-ostree-deployment.html new file mode 100644 index 0000000..bcac84d --- /dev/null +++ b/apidoc/html/ostree-ostree-deployment.html @@ -0,0 +1,647 @@ + + + + +ostree-deployment: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

ostree-deployment

+

ostree-deployment

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+guint + +ostree_deployment_hash () +
+gboolean + +ostree_deployment_equal () +
+OstreeDeployment * + +ostree_deployment_new () +
+int + +ostree_deployment_get_index () +
const char * + +ostree_deployment_get_osname () +
+int + +ostree_deployment_get_deployserial () +
const char * + +ostree_deployment_get_csum () +
const char * + +ostree_deployment_get_bootcsum () +
+int + +ostree_deployment_get_bootserial () +
+OstreeBootconfigParser * + +ostree_deployment_get_bootconfig () +
+GKeyFile * + +ostree_deployment_get_origin () +
+char * + +ostree_deployment_get_origin_relpath () +
+OstreeDeploymentUnlockedState + +ostree_deployment_get_unlocked () +
+gboolean + +ostree_deployment_is_pinned () +
+gboolean + +ostree_deployment_is_staged () +
+void + +ostree_deployment_set_index () +
+void + +ostree_deployment_set_bootserial () +
+void + +ostree_deployment_set_bootconfig () +
+void + +ostree_deployment_set_origin () +
+void + +ostree_deployment_origin_remove_transient_state () +
+OstreeDeployment * + +ostree_deployment_clone () +
const char * + +ostree_deployment_unlocked_state_to_string () +
+
+
+

Types and Values

+
++++ + + + + +
 OstreeDeployment
+
+
+

Description

+
+
+

Functions

+
+

ostree_deployment_hash ()

+
guint
+ostree_deployment_hash (gconstpointer v);
+
+
+
+

ostree_deployment_equal ()

+
gboolean
+ostree_deployment_equal (gconstpointer ap,
+                         gconstpointer bp);
+
+

Parameters

+
+++++ + + + + + + + + + + + + +

ap

A deployment.

[type OstreeDeployment]

bp

A deployment.

[type OstreeDeployment]
+
+
+

Returns

+

TRUE if deployments have the same osname, csum, and deployserial

+
+
+
+
+

ostree_deployment_new ()

+
OstreeDeployment *
+ostree_deployment_new (int index,
+                       const char *osname,
+                       const char *csum,
+                       int deployserial,
+                       const char *bootcsum,
+                       int bootserial);
+
+
+
+

ostree_deployment_get_index ()

+
int
+ostree_deployment_get_index (OstreeDeployment *self);
+
+
+
+

ostree_deployment_get_osname ()

+
const char *
+ostree_deployment_get_osname (OstreeDeployment *self);
+
+
+
+

ostree_deployment_get_deployserial ()

+
int
+ostree_deployment_get_deployserial (OstreeDeployment *self);
+
+
+
+

ostree_deployment_get_csum ()

+
const char *
+ostree_deployment_get_csum (OstreeDeployment *self);
+
+
+
+

ostree_deployment_get_bootcsum ()

+
const char *
+ostree_deployment_get_bootcsum (OstreeDeployment *self);
+
+
+
+

ostree_deployment_get_bootserial ()

+
int
+ostree_deployment_get_bootserial (OstreeDeployment *self);
+
+
+
+

ostree_deployment_get_bootconfig ()

+
OstreeBootconfigParser *
+ostree_deployment_get_bootconfig (OstreeDeployment *self);
+
+

Parameters

+
+++++ + + + + + +

self

Deployment

 
+
+
+

Returns

+

Boot configuration.

+

[transfer none]

+
+
+
+
+

ostree_deployment_get_origin ()

+
GKeyFile *
+ostree_deployment_get_origin (OstreeDeployment *self);
+
+

Parameters

+
+++++ + + + + + +

self

Deployment

 
+
+
+

Returns

+

Origin.

+

[transfer none]

+
+
+
+
+

ostree_deployment_get_origin_relpath ()

+
char *
+ostree_deployment_get_origin_relpath (OstreeDeployment *self);
+

Note this function only returns a *relative* path - if you want to +access, it, you must either use fd-relative api such as openat(), +or concatenate it with the full ostree_sysroot_get_path().

+
+

Parameters

+
+++++ + + + + + +

self

A deployment

 
+
+
+

Returns

+

Path to deployment root directory, relative to sysroot.

+

[transfer full]

+
+
+
+
+

ostree_deployment_get_unlocked ()

+
OstreeDeploymentUnlockedState
+ostree_deployment_get_unlocked (OstreeDeployment *self);
+

Since: 2016.4

+
+
+
+

ostree_deployment_is_pinned ()

+
gboolean
+ostree_deployment_is_pinned (OstreeDeployment *self);
+

See ostree_sysroot_deployment_set_pinned().

+
+

Parameters

+
+++++ + + + + + +

self

Deployment

 
+
+
+

Returns

+

TRUE if deployment will not be subject to GC

+
+

Since: 2018.3

+
+
+
+

ostree_deployment_is_staged ()

+
gboolean
+ostree_deployment_is_staged (OstreeDeployment *self);
+
+

Parameters

+
+++++ + + + + + +

self

Deployment

 
+
+
+

Returns

+

TRUE if deployment should be "finalized" at shutdown time

+
+

Since: 2018.3

+
+
+
+

ostree_deployment_set_index ()

+
void
+ostree_deployment_set_index (OstreeDeployment *self,
+                             int index);
+
+
+
+

ostree_deployment_set_bootserial ()

+
void
+ostree_deployment_set_bootserial (OstreeDeployment *self,
+                                  int index);
+
+
+
+

ostree_deployment_set_bootconfig ()

+
void
+ostree_deployment_set_bootconfig (OstreeDeployment *self,
+                                  OstreeBootconfigParser *bootconfig);
+
+
+
+

ostree_deployment_set_origin ()

+
void
+ostree_deployment_set_origin (OstreeDeployment *self,
+                              GKeyFile *origin);
+
+
+
+

ostree_deployment_origin_remove_transient_state ()

+
void
+ostree_deployment_origin_remove_transient_state
+                               (GKeyFile *origin);
+

The intention of an origin file is primarily describe the "inputs" that +resulted in a deployment, and it's commonly used to derive the new state. For +example, a key value (in pure libostree mode) is the "refspec". However, +libostree (or other applications) may want to store "transient" state that +should not be carried across upgrades.

+

This function just removes all members of the libostree-transient group. +The name of that group is available to all libostree users; best practice +would be to prefix values underneath there with a short identifier for your +software.

+

Additionally, this function will remove the origin/unlocked and +origin/override-commit members; these should be considered transient state +that should have been under an explicit group.

+
+

Parameters

+
+++++ + + + + + +

origin

An origin

 
+
+

Since: 2018.3

+
+
+
+

ostree_deployment_clone ()

+
OstreeDeployment *
+ostree_deployment_clone (OstreeDeployment *self);
+
+

Parameters

+
+++++ + + + + + +

self

Deployment

 
+
+
+

Returns

+

New deep copy of self +.

+

[transfer full]

+
+
+
+
+

ostree_deployment_unlocked_state_to_string ()

+
const char *
+ostree_deployment_unlocked_state_to_string
+                               (OstreeDeploymentUnlockedState state);
+

Since: 2016.4

+
+
+
+

Types and Values

+
+

OstreeDeployment

+
typedef struct {
+  GObject       parent_instance;
+
+  int index;
+  char *osname;
+  char *csum;
+  int deployserial;
+  char *bootcsum;
+  int bootserial;
+  OstreeBootconfigParser *bootconfig;
+  GKeyFile *origin;
+  OstreeDeploymentUnlockedState unlocked;
+  gboolean staged;
+} OstreeDeployment;
+
+
+

Members

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

int index;

Global offset

 

char *osname;

  

char *csum;

OSTree checksum of tree

 

int deployserial;

How many times this particular csum appears in deployment list

 

char *bootcsum;

Checksum of kernel+initramfs

 

int bootserial;

An integer assigned to this tree per its ${bootcsum}

 

OstreeBootconfigParser *bootconfig;

Bootloader configuration

 

GKeyFile *origin;

How to construct an upgraded version of this tree

 

OstreeDeploymentUnlockedState unlocked;

The unlocked state

 

gboolean staged;

TRUE iff this deployment is staged

 
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-diff.html b/apidoc/html/ostree-ostree-diff.html new file mode 100644 index 0000000..eaddbd6 --- /dev/null +++ b/apidoc/html/ostree-ostree-diff.html @@ -0,0 +1,369 @@ + + + + +ostree-diff: OSTree API references + + + + + + + + + + + + + + + + +
+
+
+ + +
+

ostree-diff

+

ostree-diff

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + +
+OstreeDiffItem * + +ostree_diff_item_ref () +
+void + +ostree_diff_item_unref () +
+gboolean + +ostree_diff_dirs () +
+gboolean + +ostree_diff_dirs_with_options () +
+void + +ostree_diff_print () +
+
+
+

Types and Values

+
++++ + + + + + + + + + + +
enumOstreeDiffFlags
structOstreeDiffItem
+
+
+

Description

+
+
+

Functions

+
+

ostree_diff_item_ref ()

+
OstreeDiffItem *
+ostree_diff_item_ref (OstreeDiffItem *diffitem);
+
+
+
+

ostree_diff_item_unref ()

+
void
+ostree_diff_item_unref (OstreeDiffItem *diffitem);
+
+
+
+

ostree_diff_dirs ()

+
gboolean
+ostree_diff_dirs (OstreeDiffFlags flags,
+                  GFile *a,
+                  GFile *b,
+                  GPtrArray *modified,
+                  GPtrArray *removed,
+                  GPtrArray *added,
+                  GCancellable *cancellable,
+                  GError **error);
+

Compute the difference between directory a + and b + as 3 separate +sets of OstreeDiffItem in modified +, removed +, and added +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

flags

Flags

 

a

First directory path, or NULL

 

b

First directory path

 

modified

Modified files.

[element-type OstreeDiffItem]

removed

Removed files.

[element-type Gio.File]

added

Added files.

[element-type Gio.File]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_diff_dirs_with_options ()

+
gboolean
+ostree_diff_dirs_with_options (OstreeDiffFlags flags,
+                               GFile *a,
+                               GFile *b,
+                               GPtrArray *modified,
+                               GPtrArray *removed,
+                               GPtrArray *added,
+                               OstreeDiffDirsOptions *options,
+                               GCancellable *cancellable,
+                               GError **error);
+

Compute the difference between directory a + and b + as 3 separate +sets of OstreeDiffItem in modified +, removed +, and added +.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

flags

Flags

 

a

First directory path, or NULL

 

b

First directory path

 

modified

Modified files.

[element-type OstreeDiffItem]

removed

Removed files.

[element-type Gio.File]

added

Added files.

[element-type Gio.File]

cancellable

Cancellable

 

options

Options.

[allow-none]

error

Error

 
+
+

Since: 2017.4

+
+
+
+

ostree_diff_print ()

+
void
+ostree_diff_print (GFile *a,
+                   GFile *b,
+                   GPtrArray *modified,
+                   GPtrArray *removed,
+                   GPtrArray *added);
+

Print the contents of a diff to stdout.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

a

First directory path

 

b

First directory path

 

modified

Modified files.

[element-type OstreeDiffItem]

removed

Removed files.

[element-type Gio.File]

added

Added files.

[element-type Gio.File]
+
+
+
+
+

Types and Values

+
+

enum OstreeDiffFlags

+
+

Members

+
+++++ + + + + + + + + + + + + +

OSTREE_DIFF_FLAGS_NONE

  

OSTREE_DIFF_FLAGS_IGNORE_XATTRS

  
+
+
+
+
+

struct OstreeDiffItem

+
struct OstreeDiffItem {
+  volatile gint refcount;
+
+  GFile *src;
+  GFile *target;
+
+  GFileInfo *src_info;
+  GFileInfo *target_info;
+
+  char *src_checksum;
+  char *target_checksum;
+};
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree-ostree-repo-file.html b/apidoc/html/ostree-ostree-repo-file.html new file mode 100644 index 0000000..1205e08 --- /dev/null +++ b/apidoc/html/ostree-ostree-repo-file.html @@ -0,0 +1,362 @@ + + + + +ostree-repo-file: OSTree API references + + + + + + + + + + + + + + + +
+
+
+ + +
+

ostree-repo-file

+

ostree-repo-file

+
+
+

Functions

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+gboolean + +ostree_repo_file_ensure_resolved () +
+gboolean + +ostree_repo_file_get_xattrs () +
+OstreeRepo * + +ostree_repo_file_get_repo () +
+OstreeRepoFile * + +ostree_repo_file_get_root () +
+void + +ostree_repo_file_tree_set_metadata () +
const char * + +ostree_repo_file_tree_get_contents_checksum () +
const char * + +ostree_repo_file_tree_get_metadata_checksum () +
+GVariant * + +ostree_repo_file_tree_get_contents () +
+GVariant * + +ostree_repo_file_tree_get_metadata () +
const char * + +ostree_repo_file_get_checksum () +
+int + +ostree_repo_file_tree_find_child () +
+gboolean + +ostree_repo_file_tree_query_child () +
+
+
+

Types and Values

+
++++ + + + + +
typedefOstreeRepoFile
+
+
+

Description

+
+
+

Functions

+
+

ostree_repo_file_ensure_resolved ()

+
gboolean
+ostree_repo_file_ensure_resolved (OstreeRepoFile *self,
+                                  GError **error);
+
+
+
+

ostree_repo_file_get_xattrs ()

+
gboolean
+ostree_repo_file_get_xattrs (OstreeRepoFile *self,
+                             GVariant **out_xattrs,
+                             GCancellable *cancellable,
+                             GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

OstreeRepoFile

 

out_xattrs

the extended attributes.

[out][optional]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

ostree_repo_file_get_repo ()

+
OstreeRepo *
+ostree_repo_file_get_repo (OstreeRepoFile *self);
+
+

Returns

+

Repository.

+

[transfer none]

+
+
+
+
+

ostree_repo_file_get_root ()

+
OstreeRepoFile *
+ostree_repo_file_get_root (OstreeRepoFile *self);
+
+

Returns

+

The root directory for the commit referenced by this file.

+

[transfer none]

+
+
+
+
+

ostree_repo_file_tree_set_metadata ()

+
void
+ostree_repo_file_tree_set_metadata (OstreeRepoFile *self,
+                                    const char *checksum,
+                                    GVariant *metadata);
+
+
+
+

ostree_repo_file_tree_get_contents_checksum ()

+
const char *
+ostree_repo_file_tree_get_contents_checksum
+                               (OstreeRepoFile *self);
+
+
+
+

ostree_repo_file_tree_get_metadata_checksum ()

+
const char *
+ostree_repo_file_tree_get_metadata_checksum
+                               (OstreeRepoFile *self);
+
+
+
+

ostree_repo_file_tree_get_contents ()

+
GVariant *
+ostree_repo_file_tree_get_contents (OstreeRepoFile *self);
+
+
+
+

ostree_repo_file_tree_get_metadata ()

+
GVariant *
+ostree_repo_file_tree_get_metadata (OstreeRepoFile *self);
+
+
+
+

ostree_repo_file_get_checksum ()

+
const char *
+ostree_repo_file_get_checksum (OstreeRepoFile *self);
+
+
+
+

ostree_repo_file_tree_find_child ()

+
int
+ostree_repo_file_tree_find_child (OstreeRepoFile *self,
+                                  const char *name,
+                                  gboolean *is_dir,
+                                  GVariant **out_container);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

OstreeRepoFile

 

name

name of the child

 

is_dir

.

[out caller-allocates]

out_container

.

[out]
+
+
+
+
+

ostree_repo_file_tree_query_child ()

+
gboolean
+ostree_repo_file_tree_query_child (OstreeRepoFile *self,
+                                   int n,
+                                   const char *attributes,
+                                   GFileQueryInfoFlags flags,
+                                   GFileInfo **out_info,
+                                   GCancellable *cancellable,
+                                   GError **error);
+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + +

self

OstreeRepoFile

 

out_info

.

[out]

cancellable

Cancellable

 

error

Error

 
+
+
+
+
+

Types and Values

+
+

OstreeRepoFile

+
typedef struct OstreeRepoFile OstreeRepoFile;
+
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/ostree.devhelp2 b/apidoc/html/ostree.devhelp2 new file mode 100644 index 0000000..ad15fe0 --- /dev/null +++ b/apidoc/html/ostree.devhelp2 @@ -0,0 +1,563 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apidoc/html/reference.html b/apidoc/html/reference.html new file mode 100644 index 0000000..272075d --- /dev/null +++ b/apidoc/html/reference.html @@ -0,0 +1,2029 @@ + + + + +API Reference: OSTree API references + + + + + + + + + + + + + + + + +
+

+API Reference

+
+
+Core repository-independent functions — Create, validate, and convert core data types +
+
+OstreeRepo: Content-addressed object store — A git-like storage system for operating system binaries +
+
+In-memory modifiable filesystem tree — Modifiable filesystem tree +
+
+Root partition mount point — Manage physical root filesystem +
+
+Progress notification system for asynchronous operations — Values representing progress +
+
+SELinux policy management — Read SELinux policy and manage filesystem labels +
+
+Simple upgrade class — Upgrade OSTree systems +
+
+GPG signature verification results — Inspect detached GPG signatures +
+
+Signature management — Sign and verify commits +
+
+ostree-bootconfig-parser +
+
+ostree-chain-input-stream +
+
+ostree-checksum-input-stream +
+
+ostree-deployment +
+
+ostree-diff +
+
+ostree-repo-file +
+
API Index
+
+
+

+API Index

+

A

+
+OstreeAsyncProgress, typedef in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_copy_state, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_finish, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_get, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_get_status, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_get_uint, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_get_uint64, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_get_variant, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_new, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_new_and_connect, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_set, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_set_status, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_set_uint, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_set_uint64, function in Progress notification system for asynchronous operations +
+
+
+ostree_async_progress_set_variant, function in Progress notification system for asynchronous operations +
+
+

B

+
+OstreeBootconfigParser, struct in ostree-bootconfig-parser +
+
+
+ostree_bootconfig_parser_clone, function in ostree-bootconfig-parser +
+
+
+ostree_bootconfig_parser_get, function in ostree-bootconfig-parser +
+
+
+ostree_bootconfig_parser_new, function in ostree-bootconfig-parser +
+
+
+ostree_bootconfig_parser_parse, function in ostree-bootconfig-parser +
+
+
+ostree_bootconfig_parser_parse_at, function in ostree-bootconfig-parser +
+
+
+ostree_bootconfig_parser_set, function in ostree-bootconfig-parser +
+
+
+ostree_bootconfig_parser_write, function in ostree-bootconfig-parser +
+
+
+ostree_bootconfig_parser_write_at, function in ostree-bootconfig-parser +
+
+
+ostree_break_hardlink, function in Core repository-independent functions +
+
+

C

+
+OstreeChainInputStream, struct in ostree-chain-input-stream +
+
+
+ostree_chain_input_stream_new, function in ostree-chain-input-stream +
+
+
+OstreeChecksumInputStream, struct in ostree-checksum-input-stream +
+
+
+ostree_checksum_b64_from_bytes, function in Core repository-independent functions +
+
+
+ostree_checksum_b64_inplace_from_bytes, function in Core repository-independent functions +
+
+
+ostree_checksum_b64_inplace_to_bytes, function in Core repository-independent functions +
+
+
+ostree_checksum_b64_to_bytes, function in Core repository-independent functions +
+
+
+ostree_checksum_bytes_peek, function in Core repository-independent functions +
+
+
+ostree_checksum_bytes_peek_validate, function in Core repository-independent functions +
+
+
+ostree_checksum_file, function in Core repository-independent functions +
+
+
+ostree_checksum_file_async, function in Core repository-independent functions +
+
+
+ostree_checksum_file_async_finish, function in Core repository-independent functions +
+
+
+ostree_checksum_file_at, function in Core repository-independent functions +
+
+
+ostree_checksum_file_from_input, function in Core repository-independent functions +
+
+
+ostree_checksum_from_bytes, function in Core repository-independent functions +
+
+
+ostree_checksum_from_bytes_v, function in Core repository-independent functions +
+
+
+ostree_checksum_inplace_from_bytes, function in Core repository-independent functions +
+
+
+ostree_checksum_inplace_to_bytes, function in Core repository-independent functions +
+
+
+ostree_checksum_input_stream_new, function in ostree-checksum-input-stream +
+
+
+ostree_checksum_to_bytes, function in Core repository-independent functions +
+
+
+ostree_checksum_to_bytes_v, function in Core repository-independent functions +
+
+
+OSTREE_CHECK_VERSION, macro in ostree-version +
+
+
+ostree_check_version, function in Core repository-independent functions +
+
+
+ostree_cmp_checksum_bytes, function in Core repository-independent functions +
+
+
+OstreeCollectionRefv, typedef in ostree-ref +
+
+
+ostree_collection_ref_dup, function in ostree-ref +
+
+
+ostree_collection_ref_dupv, function in ostree-ref +
+
+
+ostree_collection_ref_equal, function in ostree-ref +
+
+
+ostree_collection_ref_free, function in ostree-ref +
+
+
+ostree_collection_ref_freev, function in ostree-ref +
+
+
+ostree_collection_ref_hash, function in ostree-ref +
+
+
+ostree_collection_ref_new, function in ostree-ref +
+
+
+OstreeCommitSizesEntry, struct in Core repository-independent functions +
+
+
+ostree_commit_get_content_checksum, function in Core repository-independent functions +
+
+
+ostree_commit_get_object_sizes, function in Core repository-independent functions +
+
+
+ostree_commit_get_parent, function in Core repository-independent functions +
+
+
+ostree_commit_get_timestamp, function in Core repository-independent functions +
+
+
+OSTREE_COMMIT_GVARIANT_FORMAT, macro in Core repository-independent functions +
+
+
+OSTREE_COMMIT_GVARIANT_STRING, macro in Core repository-independent functions +
+
+
+ostree_commit_sizes_entry_copy, function in Core repository-independent functions +
+
+
+ostree_commit_sizes_entry_free, function in Core repository-independent functions +
+
+
+ostree_commit_sizes_entry_new, function in Core repository-independent functions +
+
+
+ostree_content_file_parse, function in Core repository-independent functions +
+
+
+ostree_content_file_parse_at, function in Core repository-independent functions +
+
+
+ostree_content_stream_parse, function in Core repository-independent functions +
+
+
+ostree_create_directory_metadata, function in Core repository-independent functions +
+
+

D

+
+OstreeDeployment, struct in ostree-deployment +
+
+
+ostree_deployment_clone, function in ostree-deployment +
+
+
+ostree_deployment_equal, function in ostree-deployment +
+
+
+ostree_deployment_get_bootconfig, function in ostree-deployment +
+
+
+ostree_deployment_get_bootcsum, function in ostree-deployment +
+
+
+ostree_deployment_get_bootserial, function in ostree-deployment +
+
+
+ostree_deployment_get_csum, function in ostree-deployment +
+
+
+ostree_deployment_get_deployserial, function in ostree-deployment +
+
+
+ostree_deployment_get_index, function in ostree-deployment +
+
+
+ostree_deployment_get_origin, function in ostree-deployment +
+
+
+ostree_deployment_get_origin_relpath, function in ostree-deployment +
+
+
+ostree_deployment_get_osname, function in ostree-deployment +
+
+
+ostree_deployment_get_unlocked, function in ostree-deployment +
+
+
+ostree_deployment_hash, function in ostree-deployment +
+
+
+ostree_deployment_is_pinned, function in ostree-deployment +
+
+
+ostree_deployment_is_staged, function in ostree-deployment +
+
+
+ostree_deployment_new, function in ostree-deployment +
+
+
+ostree_deployment_origin_remove_transient_state, function in ostree-deployment +
+
+
+ostree_deployment_set_bootconfig, function in ostree-deployment +
+
+
+ostree_deployment_set_bootserial, function in ostree-deployment +
+
+
+ostree_deployment_set_index, function in ostree-deployment +
+
+
+ostree_deployment_set_origin, function in ostree-deployment +
+
+
+ostree_deployment_unlocked_state_to_string, function in ostree-deployment +
+
+
+OstreeDiffFlags, enum in ostree-diff +
+
+
+OstreeDiffItem, struct in ostree-diff +
+
+
+ostree_diff_dirs, function in ostree-diff +
+
+
+ostree_diff_dirs_with_options, function in ostree-diff +
+
+
+ostree_diff_item_ref, function in ostree-diff +
+
+
+ostree_diff_item_unref, function in ostree-diff +
+
+
+ostree_diff_print, function in ostree-diff +
+
+
+OSTREE_DIRMETA_GVARIANT_FORMAT, macro in Core repository-independent functions +
+
+
+OSTREE_DIRMETA_GVARIANT_STRING, macro in Core repository-independent functions +
+
+

F

+
+OSTREE_FILEMETA_GVARIANT_FORMAT, macro in Core repository-independent functions +
+
+
+OSTREE_FILEMETA_GVARIANT_STRING, macro in Core repository-independent functions +
+
+

G

+
+OstreeGpgError, enum in GPG signature verification results +
+
+
+OstreeGpgSignatureAttr, enum in GPG signature verification results +
+
+
+OstreeGpgSignatureFormatFlags, enum in GPG signature verification results +
+
+
+OstreeGpgVerifyResult, typedef in GPG signature verification results +
+
+
+ostree_gpg_verify_result_count_all, function in GPG signature verification results +
+
+
+ostree_gpg_verify_result_count_valid, function in GPG signature verification results +
+
+
+ostree_gpg_verify_result_describe, function in GPG signature verification results +
+
+
+ostree_gpg_verify_result_describe_variant, function in GPG signature verification results +
+
+
+ostree_gpg_verify_result_get, function in GPG signature verification results +
+
+
+ostree_gpg_verify_result_get_all, function in GPG signature verification results +
+
+
+ostree_gpg_verify_result_lookup, function in GPG signature verification results +
+
+
+ostree_gpg_verify_result_require_valid_signature, function in GPG signature verification results +
+
+

H

+
+ostree_hash_object_name, function in Core repository-independent functions +
+
+

K

+
+OstreeKernelArgs, struct in ostree-kernel-args +
+
+
+ostree_kernel_args_append, function in ostree-kernel-args +
+
+
+ostree_kernel_args_append_argv, function in ostree-kernel-args +
+
+
+ostree_kernel_args_append_argv_filtered, function in ostree-kernel-args +
+
+
+ostree_kernel_args_append_proc_cmdline, function in ostree-kernel-args +
+
+
+ostree_kernel_args_cleanup, function in ostree-kernel-args +
+
+
+ostree_kernel_args_delete, function in ostree-kernel-args +
+
+
+ostree_kernel_args_delete_key_entry, function in ostree-kernel-args +
+
+
+ostree_kernel_args_free, function in ostree-kernel-args +
+
+
+ostree_kernel_args_from_string, function in ostree-kernel-args +
+
+
+ostree_kernel_args_get_last_value, function in ostree-kernel-args +
+
+
+ostree_kernel_args_new, function in ostree-kernel-args +
+
+
+ostree_kernel_args_new_replace, function in ostree-kernel-args +
+
+
+ostree_kernel_args_parse_append, function in ostree-kernel-args +
+
+
+ostree_kernel_args_replace, function in ostree-kernel-args +
+
+
+ostree_kernel_args_replace_argv, function in ostree-kernel-args +
+
+
+ostree_kernel_args_replace_take, function in ostree-kernel-args +
+
+
+ostree_kernel_args_to_string, function in ostree-kernel-args +
+
+
+ostree_kernel_args_to_strv, function in ostree-kernel-args +
+
+

M

+
+OSTREE_MAX_METADATA_SIZE, macro in Core repository-independent functions +
+
+
+OSTREE_MAX_METADATA_WARN_SIZE, macro in Core repository-independent functions +
+
+
+ostree_metadata_variant_type, function in Core repository-independent functions +
+
+
+OSTREE_META_KEY_DEPLOY_COLLECTION_ID, macro in ostree-repo-experimental +
+
+
+OstreeMutableTree, typedef in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_check_error, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_ensure_dir, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_ensure_parent_dirs, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_fill_empty_from_dirtree, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_get_contents_checksum, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_get_files, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_get_metadata_checksum, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_get_subdirs, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_lookup, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_new, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_new_from_checksum, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_remove, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_replace_file, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_set_contents_checksum, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_set_metadata_checksum, function in In-memory modifiable filesystem tree +
+
+
+ostree_mutable_tree_walk, function in In-memory modifiable filesystem tree +
+
+

O

+
+OstreeObjectType, enum in Core repository-independent functions +
+
+
+ostree_object_from_string, function in Core repository-independent functions +
+
+
+ostree_object_name_deserialize, function in Core repository-independent functions +
+
+
+ostree_object_name_serialize, function in Core repository-independent functions +
+
+
+ostree_object_to_string, function in Core repository-independent functions +
+
+
+ostree_object_type_from_string, function in Core repository-independent functions +
+
+
+OSTREE_OBJECT_TYPE_IS_META, macro in Core repository-independent functions +
+
+
+OSTREE_OBJECT_TYPE_LAST, macro in Core repository-independent functions +
+
+
+ostree_object_type_to_string, function in Core repository-independent functions +
+
+

P

+
+ostree_parse_refspec, function in Core repository-independent functions +
+
+

R

+
+ostree_raw_file_to_archive_z2_stream, function in Core repository-independent functions +
+
+
+ostree_raw_file_to_archive_z2_stream_with_options, function in Core repository-independent functions +
+
+
+ostree_raw_file_to_content_stream, function in Core repository-independent functions +
+
+
+OSTREE_RELEASE_VERSION, macro in ostree-version +
+
+
+OstreeRemote, struct in ostree-remote +
+
+
+ostree_remote_get_name, function in ostree-remote +
+
+
+ostree_remote_get_url, function in ostree-remote +
+
+
+ostree_remote_ref, function in ostree-remote +
+
+
+ostree_remote_unref, function in ostree-remote +
+
+
+OstreeRepo, typedef in OstreeRepo +
+
+
+OstreeRepoCheckoutAtOptions, struct in OstreeRepo +
+
+
+OstreeRepoCheckoutMode, enum in OstreeRepo +
+
+
+OstreeRepoCheckoutOverwriteMode, enum in OstreeRepo +
+
+
+OstreeRepoCommitFilter, user_function in OstreeRepo +
+
+
+OstreeRepoCommitFilterResult, enum in OstreeRepo +
+
+
+OstreeRepoCommitIterResult, enum in OstreeRepo +
+
+
+OstreeRepoCommitModifier, typedef in OstreeRepo +
+
+
+OstreeRepoCommitModifierFlags, enum in OstreeRepo +
+
+
+OstreeRepoCommitModifierXattrCallback, user_function in OstreeRepo +
+
+
+OstreeRepoCommitState, enum in OstreeRepo +
+
+
+OstreeRepoCommitTraverseFlags, enum in OstreeRepo +
+
+
+OstreeRepoFile, typedef in ostree-repo-file +
+
+
+OstreeRepoFinder, struct in ostree-repo-finder +
+
+
+OstreeRepoFinderAvahi, struct in OstreeRepoFinderAvahi +
+
+
+OstreeRepoFinderConfig, struct in OstreeRepoFinderConfig +
+
+
+OstreeRepoFinderMount, struct in OstreeRepoFinderMount +
+
+
+OstreeRepoFinderOverride, struct in OstreeRepoFinderOverride +
+
+
+OstreeRepoFinderResultv, typedef in ostree-repo-finder +
+
+
+OstreeRepoListObjectsFlags, enum in OstreeRepo +
+
+
+OstreeRepoListRefsExtFlags, enum in OstreeRepo +
+
+
+OstreeRepoMode, enum in OstreeRepo +
+
+
+OstreeRepoPruneFlags, enum in OstreeRepo +
+
+
+OstreeRepoPullFlags, enum in OstreeRepo +
+
+
+OstreeRepoRemoteChange, enum in OstreeRepo +
+
+
+OstreeRepoResolveRevExtFlags, enum in OstreeRepo +
+
+
+OstreeRepoTransactionStats, struct in OstreeRepo +
+
+
+ostree_repo_abort_transaction, function in OstreeRepo +
+
+
+ostree_repo_add_gpg_signature_summary, function in OstreeRepo +
+
+
+ostree_repo_append_gpg_signature, function in OstreeRepo +
+
+
+ostree_repo_checkout_at, function in OstreeRepo +
+
+
+ostree_repo_checkout_at_options_set_devino, function in OstreeRepo +
+
+
+ostree_repo_checkout_gc, function in OstreeRepo +
+
+
+ostree_repo_checkout_tree, function in OstreeRepo +
+
+
+ostree_repo_checkout_tree_at, function in OstreeRepo +
+
+
+ostree_repo_commit_modifier_new, function in OstreeRepo +
+
+
+ostree_repo_commit_modifier_ref, function in OstreeRepo +
+
+
+ostree_repo_commit_modifier_set_devino_cache, function in OstreeRepo +
+
+
+ostree_repo_commit_modifier_set_sepolicy, function in OstreeRepo +
+
+
+ostree_repo_commit_modifier_set_sepolicy_from_commit, function in OstreeRepo +
+
+
+ostree_repo_commit_modifier_set_xattr_callback, function in OstreeRepo +
+
+
+ostree_repo_commit_modifier_unref, function in OstreeRepo +
+
+
+ostree_repo_commit_transaction, function in OstreeRepo +
+
+
+ostree_repo_commit_traverse_iter_cleanup, function in OstreeRepo +
+
+
+ostree_repo_commit_traverse_iter_clear, function in OstreeRepo +
+
+
+ostree_repo_commit_traverse_iter_get_dir, function in OstreeRepo +
+
+
+ostree_repo_commit_traverse_iter_get_file, function in OstreeRepo +
+
+
+ostree_repo_commit_traverse_iter_init_commit, function in OstreeRepo +
+
+
+ostree_repo_commit_traverse_iter_init_dirtree, function in OstreeRepo +
+
+
+ostree_repo_commit_traverse_iter_next, function in OstreeRepo +
+
+
+ostree_repo_copy_config, function in OstreeRepo +
+
+
+ostree_repo_create, function in OstreeRepo +
+
+
+ostree_repo_create_at, function in OstreeRepo +
+
+
+ostree_repo_delete_object, function in OstreeRepo +
+
+
+ostree_repo_devino_cache_get_type, function in OstreeRepo +
+
+
+ostree_repo_devino_cache_new, function in OstreeRepo +
+
+
+ostree_repo_devino_cache_ref, function in OstreeRepo +
+
+
+ostree_repo_devino_cache_unref, function in OstreeRepo +
+
+
+ostree_repo_equal, function in OstreeRepo +
+
+
+ostree_repo_export_tree_to_archive, function in OstreeRepo +
+
+
+ostree_repo_file_ensure_resolved, function in ostree-repo-file +
+
+
+ostree_repo_file_get_checksum, function in ostree-repo-file +
+
+
+ostree_repo_file_get_repo, function in ostree-repo-file +
+
+
+ostree_repo_file_get_root, function in ostree-repo-file +
+
+
+ostree_repo_file_get_xattrs, function in ostree-repo-file +
+
+
+ostree_repo_file_tree_find_child, function in ostree-repo-file +
+
+
+ostree_repo_file_tree_get_contents, function in ostree-repo-file +
+
+
+ostree_repo_file_tree_get_contents_checksum, function in ostree-repo-file +
+
+
+ostree_repo_file_tree_get_metadata, function in ostree-repo-file +
+
+
+ostree_repo_file_tree_get_metadata_checksum, function in ostree-repo-file +
+
+
+ostree_repo_file_tree_query_child, function in ostree-repo-file +
+
+
+ostree_repo_file_tree_set_metadata, function in ostree-repo-file +
+
+
+ostree_repo_finder_resolve_all_async, function in ostree-repo-finder +
+
+
+ostree_repo_finder_resolve_all_finish, function in ostree-repo-finder +
+
+
+ostree_repo_finder_resolve_async, function in ostree-repo-finder +
+
+
+ostree_repo_finder_resolve_finish, function in ostree-repo-finder +
+
+
+ostree_repo_finder_result_compare, function in ostree-repo-finder +
+
+
+ostree_repo_finder_result_dup, function in ostree-repo-finder +
+
+
+ostree_repo_finder_result_free, function in ostree-repo-finder +
+
+
+ostree_repo_finder_result_freev, function in ostree-repo-finder +
+
+
+ostree_repo_finder_result_new, function in ostree-repo-finder +
+
+
+ostree_repo_find_remotes_async, function in ostree-repo-experimental +
+
+
+ostree_repo_find_remotes_finish, function in ostree-repo-experimental +
+
+
+ostree_repo_fsck_object, function in OstreeRepo +
+
+
+ostree_repo_get_bootloader, function in OstreeRepo +
+
+
+ostree_repo_get_collection_id, function in ostree-misc-experimental +
+
+
+ostree_repo_get_config, function in OstreeRepo +
+
+
+ostree_repo_get_default_repo_finders, function in OstreeRepo +
+
+
+ostree_repo_get_dfd, function in OstreeRepo +
+
+
+ostree_repo_get_disable_fsync, function in OstreeRepo +
+
+
+ostree_repo_get_min_free_space_bytes, function in OstreeRepo +
+
+
+ostree_repo_get_mode, function in OstreeRepo +
+
+
+ostree_repo_get_parent, function in OstreeRepo +
+
+
+ostree_repo_get_path, function in OstreeRepo +
+
+
+ostree_repo_get_remote_boolean_option, function in OstreeRepo +
+
+
+ostree_repo_get_remote_list_option, function in OstreeRepo +
+
+
+ostree_repo_get_remote_option, function in OstreeRepo +
+
+
+ostree_repo_gpg_verify_data, function in OstreeRepo +
+
+
+ostree_repo_hash, function in OstreeRepo +
+
+
+ostree_repo_has_object, function in OstreeRepo +
+
+
+ostree_repo_import_archive_to_mtree, function in OstreeRepo +
+
+
+ostree_repo_import_object_from, function in OstreeRepo +
+
+
+ostree_repo_import_object_from_with_trust, function in OstreeRepo +
+
+
+ostree_repo_is_system, function in OstreeRepo +
+
+
+ostree_repo_is_writable, function in OstreeRepo +
+
+
+ostree_repo_list_collection_refs, function in ostree-misc-experimental +
+
+
+ostree_repo_list_commit_objects_starting_with, function in OstreeRepo +
+
+
+ostree_repo_list_objects, function in OstreeRepo +
+
+
+OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE, macro in OstreeRepo +
+
+
+ostree_repo_list_refs, function in OstreeRepo +
+
+
+ostree_repo_list_refs_ext, function in OstreeRepo +
+
+
+ostree_repo_list_static_delta_names, function in OstreeRepo +
+
+
+ostree_repo_load_commit, function in OstreeRepo +
+
+
+ostree_repo_load_file, function in OstreeRepo +
+
+
+ostree_repo_load_object_stream, function in OstreeRepo +
+
+
+ostree_repo_load_variant, function in OstreeRepo +
+
+
+ostree_repo_load_variant_if_exists, function in OstreeRepo +
+
+
+ostree_repo_mark_commit_partial, function in OstreeRepo +
+
+
+ostree_repo_mark_commit_partial_reason, function in OstreeRepo +
+
+
+OSTREE_REPO_METADATA_REF, macro in ostree-repo-experimental +
+
+
+ostree_repo_mode_from_string, function in OstreeRepo +
+
+
+ostree_repo_new, function in OstreeRepo +
+
+
+ostree_repo_new_default, function in OstreeRepo +
+
+
+ostree_repo_new_for_sysroot_path, function in OstreeRepo +
+
+
+ostree_repo_open, function in OstreeRepo +
+
+
+ostree_repo_open_at, function in OstreeRepo +
+
+
+ostree_repo_prepare_transaction, function in OstreeRepo +
+
+
+ostree_repo_prune, function in OstreeRepo +
+
+
+ostree_repo_prune_from_reachable, function in OstreeRepo +
+
+
+ostree_repo_prune_static_deltas, function in OstreeRepo +
+
+
+ostree_repo_pull, function in OstreeRepo +
+
+
+ostree_repo_pull_default_console_progress_changed, function in OstreeRepo +
+
+
+ostree_repo_pull_from_remotes_async, function in ostree-repo-experimental +
+
+
+ostree_repo_pull_from_remotes_finish, function in ostree-repo-experimental +
+
+
+ostree_repo_pull_one_dir, function in OstreeRepo +
+
+
+ostree_repo_pull_with_options, function in OstreeRepo +
+
+
+ostree_repo_query_object_storage_size, function in OstreeRepo +
+
+
+ostree_repo_read_commit, function in OstreeRepo +
+
+
+ostree_repo_read_commit_detached_metadata, function in OstreeRepo +
+
+
+ostree_repo_regenerate_summary, function in OstreeRepo +
+
+
+ostree_repo_reload_config, function in OstreeRepo +
+
+
+ostree_repo_remote_add, function in OstreeRepo +
+
+
+ostree_repo_remote_change, function in OstreeRepo +
+
+
+ostree_repo_remote_delete, function in OstreeRepo +
+
+
+ostree_repo_remote_fetch_summary, function in OstreeRepo +
+
+
+ostree_repo_remote_fetch_summary_with_options, function in OstreeRepo +
+
+
+ostree_repo_remote_get_gpg_verify, function in OstreeRepo +
+
+
+ostree_repo_remote_get_gpg_verify_summary, function in OstreeRepo +
+
+
+ostree_repo_remote_get_url, function in OstreeRepo +
+
+
+ostree_repo_remote_gpg_import, function in OstreeRepo +
+
+
+ostree_repo_remote_list, function in OstreeRepo +
+
+
+ostree_repo_remote_list_collection_refs, function in ostree-misc-experimental +
+
+
+ostree_repo_remote_list_refs, function in OstreeRepo +
+
+
+ostree_repo_resolve_collection_ref, function in ostree-misc-experimental +
+
+
+ostree_repo_resolve_keyring_for_collection, function in ostree-repo-experimental +
+
+
+ostree_repo_resolve_rev, function in OstreeRepo +
+
+
+ostree_repo_resolve_rev_ext, function in OstreeRepo +
+
+
+ostree_repo_scan_hardlinks, function in OstreeRepo +
+
+
+ostree_repo_set_alias_ref_immediate, function in OstreeRepo +
+
+
+ostree_repo_set_cache_dir, function in OstreeRepo +
+
+
+ostree_repo_set_collection_id, function in ostree-misc-experimental +
+
+
+ostree_repo_set_collection_ref_immediate, function in ostree-misc-experimental +
+
+
+ostree_repo_set_disable_fsync, function in OstreeRepo +
+
+
+ostree_repo_set_ref_immediate, function in OstreeRepo +
+
+
+ostree_repo_sign_commit, function in OstreeRepo +
+
+
+ostree_repo_sign_delta, function in OstreeRepo +
+
+
+ostree_repo_static_delta_execute_offline, function in OstreeRepo +
+
+
+ostree_repo_static_delta_generate, function in OstreeRepo +
+
+
+ostree_repo_transaction_set_collection_ref, function in ostree-misc-experimental +
+
+
+ostree_repo_transaction_set_ref, function in OstreeRepo +
+
+
+ostree_repo_transaction_set_refspec, function in OstreeRepo +
+
+
+ostree_repo_traverse_commit, function in OstreeRepo +
+
+
+ostree_repo_traverse_commit_union, function in OstreeRepo +
+
+
+ostree_repo_traverse_commit_union_with_parents, function in OstreeRepo +
+
+
+ostree_repo_traverse_new_parents, function in OstreeRepo +
+
+
+ostree_repo_traverse_new_reachable, function in OstreeRepo +
+
+
+ostree_repo_traverse_parents_get_commits, function in OstreeRepo +
+
+
+ostree_repo_traverse_reachable_refs, function in OstreeRepo +
+
+
+ostree_repo_verify_commit, function in OstreeRepo +
+
+
+ostree_repo_verify_commit_ext, function in OstreeRepo +
+
+
+ostree_repo_verify_commit_for_remote, function in OstreeRepo +
+
+
+ostree_repo_verify_summary, function in OstreeRepo +
+
+
+ostree_repo_write_archive_to_mtree, function in OstreeRepo +
+
+
+ostree_repo_write_archive_to_mtree_from_fd, function in OstreeRepo +
+
+
+ostree_repo_write_commit, function in OstreeRepo +
+
+
+ostree_repo_write_commit_detached_metadata, function in OstreeRepo +
+
+
+ostree_repo_write_commit_with_time, function in OstreeRepo +
+
+
+ostree_repo_write_config, function in OstreeRepo +
+
+
+ostree_repo_write_content, function in OstreeRepo +
+
+
+ostree_repo_write_content_async, function in OstreeRepo +
+
+
+ostree_repo_write_content_finish, function in OstreeRepo +
+
+
+ostree_repo_write_content_trusted, function in OstreeRepo +
+
+
+ostree_repo_write_dfd_to_mtree, function in OstreeRepo +
+
+
+ostree_repo_write_directory_to_mtree, function in OstreeRepo +
+
+
+ostree_repo_write_metadata, function in OstreeRepo +
+
+
+ostree_repo_write_metadata_async, function in OstreeRepo +
+
+
+ostree_repo_write_metadata_finish, function in OstreeRepo +
+
+
+ostree_repo_write_metadata_stream_trusted, function in OstreeRepo +
+
+
+ostree_repo_write_metadata_trusted, function in OstreeRepo +
+
+
+ostree_repo_write_mtree, function in OstreeRepo +
+
+

S

+
+OstreeSePolicy, typedef in SELinux policy management +
+
+
+OstreeSePolicyRestoreconFlags, enum in SELinux policy management +
+
+
+ostree_sepolicy_fscreatecon_cleanup, function in SELinux policy management +
+
+
+ostree_sepolicy_get_csum, function in SELinux policy management +
+
+
+ostree_sepolicy_get_label, function in SELinux policy management +
+
+
+ostree_sepolicy_get_name, function in SELinux policy management +
+
+
+ostree_sepolicy_get_path, function in SELinux policy management +
+
+
+ostree_sepolicy_new, function in SELinux policy management +
+
+
+ostree_sepolicy_new_at, function in SELinux policy management +
+
+
+ostree_sepolicy_restorecon, function in SELinux policy management +
+
+
+ostree_sepolicy_setfscreatecon, function in SELinux policy management +
+
+
+OstreeSign, struct in Signature management +
+
+
+ostree_sign_add_pk, function in Signature management +
+
+
+ostree_sign_clear_keys, function in Signature management +
+
+
+ostree_sign_commit, function in Signature management +
+
+
+ostree_sign_commit_verify, function in Signature management +
+
+
+ostree_sign_data, function in Signature management +
+
+
+ostree_sign_data_verify, function in Signature management +
+
+
+ostree_sign_get_all, function in Signature management +
+
+
+ostree_sign_get_by_name, function in Signature management +
+
+
+ostree_sign_get_name, function in Signature management +
+
+
+ostree_sign_load_pk, function in Signature management +
+
+
+ostree_sign_metadata_format, function in Signature management +
+
+
+ostree_sign_metadata_key, function in Signature management +
+
+
+ostree_sign_set_pk, function in Signature management +
+
+
+ostree_sign_set_sk, function in Signature management +
+
+
+ostree_sign_summary, function in Signature management +
+
+
+OstreeStaticDeltaGenerateOpt, enum in OstreeRepo +
+
+
+OSTREE_SUMMARY_GVARIANT_FORMAT, macro in Core repository-independent functions +
+
+
+OSTREE_SUMMARY_GVARIANT_STRING, macro in Core repository-independent functions +
+
+
+OstreeSysroot, typedef in Root partition mount point +
+
+
+OstreeSysrootSimpleWriteDeploymentFlags, enum in Root partition mount point +
+
+
+OstreeSysrootUpgrader, typedef in Simple upgrade class +
+
+
+OstreeSysrootUpgraderFlags, enum in Simple upgrade class +
+
+
+OstreeSysrootUpgraderPullFlags, enum in Simple upgrade class +
+
+
+ostree_sysroot_cleanup, function in Root partition mount point +
+
+
+ostree_sysroot_cleanup_prune_repo, function in Root partition mount point +
+
+
+ostree_sysroot_deployment_set_kargs, function in Root partition mount point +
+
+
+ostree_sysroot_deployment_set_mutable, function in Root partition mount point +
+
+
+ostree_sysroot_deployment_set_pinned, function in Root partition mount point +
+
+
+ostree_sysroot_deployment_unlock, function in Root partition mount point +
+
+
+ostree_sysroot_deploy_tree, function in Root partition mount point +
+
+
+ostree_sysroot_ensure_initialized, function in Root partition mount point +
+
+
+ostree_sysroot_get_booted_deployment, function in Root partition mount point +
+
+
+ostree_sysroot_get_bootversion, function in Root partition mount point +
+
+
+ostree_sysroot_get_deployments, function in Root partition mount point +
+
+
+ostree_sysroot_get_deployment_directory, function in Root partition mount point +
+
+
+ostree_sysroot_get_deployment_dirpath, function in Root partition mount point +
+
+
+ostree_sysroot_get_deployment_origin_path, function in Root partition mount point +
+
+
+ostree_sysroot_get_fd, function in Root partition mount point +
+
+
+ostree_sysroot_get_merge_deployment, function in Root partition mount point +
+
+
+ostree_sysroot_get_path, function in Root partition mount point +
+
+
+ostree_sysroot_get_repo, function in Root partition mount point +
+
+
+ostree_sysroot_get_staged_deployment, function in Root partition mount point +
+
+
+ostree_sysroot_get_subbootversion, function in Root partition mount point +
+
+
+ostree_sysroot_initialize, function in Root partition mount point +
+
+
+ostree_sysroot_init_osname, function in Root partition mount point +
+
+
+ostree_sysroot_is_booted, function in Root partition mount point +
+
+
+ostree_sysroot_load, function in Root partition mount point +
+
+
+ostree_sysroot_load_if_changed, function in Root partition mount point +
+
+
+ostree_sysroot_lock, function in Root partition mount point +
+
+
+ostree_sysroot_lock_async, function in Root partition mount point +
+
+
+ostree_sysroot_lock_finish, function in Root partition mount point +
+
+
+ostree_sysroot_new, function in Root partition mount point +
+
+
+ostree_sysroot_new_default, function in Root partition mount point +
+
+
+ostree_sysroot_origin_new_from_refspec, function in Root partition mount point +
+
+
+ostree_sysroot_prepare_cleanup, function in Root partition mount point +
+
+
+ostree_sysroot_query_deployments_for, function in Root partition mount point +
+
+
+ostree_sysroot_repo, function in Root partition mount point +
+
+
+ostree_sysroot_set_mount_namespace_in_use, function in Root partition mount point +
+
+
+ostree_sysroot_simple_write_deployment, function in Root partition mount point +
+
+
+ostree_sysroot_stage_tree, function in Root partition mount point +
+
+
+ostree_sysroot_try_lock, function in Root partition mount point +
+
+
+ostree_sysroot_unload, function in Root partition mount point +
+
+
+ostree_sysroot_unlock, function in Root partition mount point +
+
+
+ostree_sysroot_upgrader_check_timestamps, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_deploy, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_dup_origin, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_get_origin, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_get_origin_description, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_new, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_new_for_os, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_new_for_os_with_flags, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_pull, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_pull_one_dir, function in Simple upgrade class +
+
+
+ostree_sysroot_upgrader_set_origin, function in Simple upgrade class +
+
+
+ostree_sysroot_write_deployments, function in Root partition mount point +
+
+
+ostree_sysroot_write_deployments_with_options, function in Root partition mount point +
+
+
+ostree_sysroot_write_origin_file, function in Root partition mount point +
+
+

T

+
+OSTREE_TREE_GVARIANT_FORMAT, macro in Core repository-independent functions +
+
+
+OSTREE_TREE_GVARIANT_STRING, macro in Core repository-independent functions +
+
+

V

+
+ostree_validate_checksum_string, function in Core repository-independent functions +
+
+
+ostree_validate_collection_id, function in ostree-misc-experimental +
+
+
+ostree_validate_remote_name, function in Core repository-independent functions +
+
+
+ostree_validate_rev, function in Core repository-independent functions +
+
+
+ostree_validate_structureof_checksum_string, function in Core repository-independent functions +
+
+
+ostree_validate_structureof_commit, function in Core repository-independent functions +
+
+
+ostree_validate_structureof_csum_v, function in Core repository-independent functions +
+
+
+ostree_validate_structureof_dirmeta, function in Core repository-independent functions +
+
+
+ostree_validate_structureof_dirtree, function in Core repository-independent functions +
+
+
+ostree_validate_structureof_file_mode, function in Core repository-independent functions +
+
+
+ostree_validate_structureof_objtype, function in Core repository-independent functions +
+
+
+OSTREE_VERSION, macro in ostree-version +
+
+
+OSTREE_VERSION_HEX, macro in ostree-version +
+
+
+OSTREE_VERSION_S, macro in ostree-version +
+
+

Y

+
+OSTREE_YEAR_VERSION, macro in ostree-version +
+
+
+
+ + + \ No newline at end of file diff --git a/apidoc/html/right-insensitive.png b/apidoc/html/right-insensitive.png new file mode 100644 index 0000000..4c95785 Binary files /dev/null and b/apidoc/html/right-insensitive.png differ diff --git a/apidoc/html/right.png b/apidoc/html/right.png new file mode 100644 index 0000000..76260ec Binary files /dev/null and b/apidoc/html/right.png differ diff --git a/apidoc/html/style.css b/apidoc/html/style.css new file mode 100644 index 0000000..b4a1493 --- /dev/null +++ b/apidoc/html/style.css @@ -0,0 +1,533 @@ +body +{ + font-family: cantarell, sans-serif; +} +.synopsis, .classsynopsis +{ + /* tango:aluminium 1/2 */ + background: #eeeeec; + background: rgba(238, 238, 236, 0.5); + border: solid 1px rgb(238, 238, 236); + padding: 0.5em; +} +.programlisting +{ + /* tango:sky blue 0/1 */ + /* fallback for no rgba support */ + background: #e6f3ff; + border: solid 1px #729fcf; + background: rgba(114, 159, 207, 0.1); + border: solid 1px rgba(114, 159, 207, 0.2); + padding: 0.5em; +} +.variablelist +{ + padding: 4px; + margin-left: 3em; +} +.variablelist td:first-child +{ + vertical-align: top; +} + +span.nowrap { + white-space: nowrap; +} + +div.gallery-float +{ + float: left; + padding: 10px; +} +div.gallery-float img +{ + border-style: none; +} +div.gallery-spacer +{ + clear: both; +} + +a, a:visited +{ + text-decoration: none; + /* tango:sky blue 2 */ + color: #3465a4; +} +a:hover +{ + text-decoration: underline; + /* tango:sky blue 1 */ + color: #729fcf; +} + +div.informaltable table +{ + border-collapse: separate; + border-spacing: 1em 0.3em; + border: none; +} + +div.informaltable table td, div.informaltable table th +{ + vertical-align: top; +} + +.function_type, +.variable_type, +.property_type, +.signal_type, +.parameter_name, +.struct_member_name, +.union_member_name, +.define_keyword, +.datatype_keyword, +.typedef_keyword +{ + text-align: right; +} + +/* dim non-primary columns */ +.c_punctuation, +.function_type, +.variable_type, +.property_type, +.signal_type, +.define_keyword, +.datatype_keyword, +.typedef_keyword, +.property_flags, +.signal_flags, +.parameter_annotations, +.enum_member_annotations, +.struct_member_annotations, +.union_member_annotations +{ + color: #888a85; +} + +.function_type a, +.function_type a:visited, +.function_type a:hover, +.property_type a, +.property_type a:visited, +.property_type a:hover, +.signal_type a, +.signal_type a:visited, +.signal_type a:hover, +.signal_flags a, +.signal_flags a:visited, +.signal_flags a:hover +{ + color: #729fcf; +} + +td p +{ + margin: 0.25em; +} + +div.table table +{ + border-collapse: collapse; + border-spacing: 0px; + /* tango:aluminium 3 */ + border: solid 1px #babdb6; +} + +div.table table td, div.table table th +{ + /* tango:aluminium 3 */ + border: solid 1px #babdb6; + padding: 3px; + vertical-align: top; +} + +div.table table th +{ + /* tango:aluminium 2 */ + background-color: #d3d7cf; +} + +h4 +{ + color: #555753; + margin-top: 1em; + margin-bottom: 1em; +} + +hr +{ + /* tango:aluminium 1 */ + color: #d3d7cf; + background: #d3d7cf; + border: none 0px; + height: 1px; + clear: both; + margin: 2.0em 0em 2.0em 0em; +} + +dl.toc dt +{ + padding-bottom: 0.25em; +} + +dl.toc > dt +{ + padding-top: 0.25em; + padding-bottom: 0.25em; + font-weight: bold; +} + +dl.toc > dl +{ + padding-bottom: 0.5em; +} + +.parameter +{ + font-style: normal; +} + +.footer +{ + padding-top: 3.5em; + /* tango:aluminium 3 */ + color: #babdb6; + text-align: center; + font-size: 80%; +} + +.informalfigure, +.figure +{ + margin: 1em; +} + +.informalexample, +.example +{ + margin-top: 1em; + margin-bottom: 1em; +} + +.warning +{ + /* tango:orange 0/1 */ + background: #ffeed9; + background: rgba(252, 175, 62, 0.1); + border-color: #ffb04f; + border-color: rgba(252, 175, 62, 0.2); +} +.note +{ + /* tango:chameleon 0/0.5 */ + background: #d8ffb2; + background: rgba(138, 226, 52, 0.1); + border-color: #abf562; + border-color: rgba(138, 226, 52, 0.2); +} +div.blockquote +{ + border-color: #eeeeec; +} +.note, .warning, div.blockquote +{ + padding: 0.5em; + border-width: 1px; + border-style: solid; + margin: 2em; +} +.note p, .warning p +{ + margin: 0; +} + +div.warning h3.title, +div.note h3.title +{ + display: none; +} + +p + div.section +{ + margin-top: 1em; +} + +div.refnamediv, +div.refsynopsisdiv, +div.refsect1, +div.refsect2, +div.toc, +div.section +{ + margin-bottom: 1em; +} + +/* blob links */ +h2 .extralinks, h3 .extralinks +{ + float: right; + /* tango:aluminium 3 */ + color: #babdb6; + font-size: 80%; + font-weight: normal; +} + +.lineart +{ + color: #d3d7cf; + font-weight: normal; +} + +.annotation +{ + /* tango:aluminium 5 */ + color: #555753; + font-weight: normal; +} + +.structfield +{ + font-style: normal; + font-weight: normal; +} + +acronym,abbr +{ + border-bottom: 1px dotted gray; +} + +.listing_frame { + /* tango:sky blue 1 */ + border: solid 1px #729fcf; + border: solid 1px rgba(114, 159, 207, 0.2); + padding: 0px; +} + +.listing_lines, .listing_code { + margin-top: 0px; + margin-bottom: 0px; + padding: 0.5em; +} +.listing_lines { + /* tango:sky blue 0.5 */ + background: #a6c5e3; + background: rgba(114, 159, 207, 0.2); + /* tango:aluminium 6 */ + color: #2e3436; +} +.listing_code { + /* tango:sky blue 0 */ + background: #e6f3ff; + background: rgba(114, 159, 207, 0.1); +} +.listing_code .programlisting { + /* override from previous */ + border: none 0px; + padding: 0px; + background: none; +} +.listing_lines pre, .listing_code pre { + margin: 0px; +} + +@media screen { + /* these have a as a first child, but since there are no parent selectors + * we can't use that. */ + a.footnote + { + position: relative; + top: 0em ! important; + } + /* this is needed so that the local anchors are displayed below the naviagtion */ + div.footnote a[name], div.refnamediv a[name], div.refsect1 a[name], div.refsect2 a[name], div.index a[name], div.glossary a[name], div.sect1 a[name] + { + display: inline-block; + position: relative; + top:-5em; + } + /* this seems to be a bug in the xsl style sheets when generating indexes */ + div.index div.index + { + top: 0em; + } + /* make space for the fixed navigation bar and add space at the bottom so that + * link targets appear somewhat close to top + */ + body + { + padding-top: 2.5em; + padding-bottom: 500px; + max-width: 60em; + } + p + { + max-width: 60em; + } + /* style and size the navigation bar */ + table.navigation#top + { + position: fixed; + background: #e2e2e2; + border-bottom: solid 1px #babdb6; + border-spacing: 5px; + margin-top: 0; + margin-bottom: 0; + top: 0; + left: 0; + z-index: 10; + } + table.navigation#top td + { + padding-left: 6px; + padding-right: 6px; + } + .navigation a, .navigation a:visited + { + /* tango:sky blue 3 */ + color: #204a87; + } + .navigation a:hover + { + /* tango:sky blue 2 */ + color: #3465a4; + } + td.shortcuts + { + /* tango:sky blue 2 */ + color: #3465a4; + font-size: 80%; + white-space: nowrap; + } + td.shortcuts .dim + { + color: #babdb6; + } + .navigation .title + { + font-size: 80%; + max-width: none; + margin: 0px; + font-weight: normal; + } +} +@media screen and (min-width: 60em) { + /* screen larger than 60em */ + body { margin: auto; } +} +@media screen and (max-width: 60em) { + /* screen less than 60em */ + #nav_hierarchy { display: none; } + #nav_interfaces { display: none; } + #nav_prerequisites { display: none; } + #nav_derived_interfaces { display: none; } + #nav_implementations { display: none; } + #nav_child_properties { display: none; } + #nav_style_properties { display: none; } + #nav_index { display: none; } + #nav_glossary { display: none; } + .gallery_image { display: none; } + .property_flags { display: none; } + .signal_flags { display: none; } + .parameter_annotations { display: none; } + .enum_member_annotations { display: none; } + .struct_member_annotations { display: none; } + .union_member_annotations { display: none; } + /* now that a column is hidden, optimize space */ + col.parameters_name { width: auto; } + col.parameters_description { width: auto; } + col.struct_members_name { width: auto; } + col.struct_members_description { width: auto; } + col.enum_members_name { width: auto; } + col.enum_members_description { width: auto; } + col.union_members_name { width: auto; } + col.union_members_description { width: auto; } + .listing_lines { display: none; } +} +@media print { + table.navigation { + visibility: collapse; + display: none; + } + div.titlepage table.navigation { + visibility: visible; + display: table; + background: #e2e2e2; + border: solid 1px #babdb6; + margin-top: 0; + margin-bottom: 0; + top: 0; + left: 0; + height: 3em; + } +} + +.hll { background-color: #ffffcc } +.c { color: #408080; font-style: italic } /* Comment */ +.err { border: 1px solid #FF0000 } /* Error */ +.k { color: #008000; font-weight: bold } /* Keyword */ +.o { color: #666666 } /* Operator */ +.ch { color: #408080; font-style: italic } /* Comment.Hashbang */ +.cm { color: #408080; font-style: italic } /* Comment.Multiline */ +.cp { color: #BC7A00 } /* Comment.Preproc */ +.cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */ +.c1 { color: #408080; font-style: italic } /* Comment.Single */ +.cs { color: #408080; font-style: italic } /* Comment.Special */ +.gd { color: #A00000 } /* Generic.Deleted */ +.ge { font-style: italic } /* Generic.Emph */ +.gr { color: #FF0000 } /* Generic.Error */ +.gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.gi { color: #00A000 } /* Generic.Inserted */ +.go { color: #888888 } /* Generic.Output */ +.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.gs { font-weight: bold } /* Generic.Strong */ +.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.gt { color: #0044DD } /* Generic.Traceback */ +.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.kp { color: #008000 } /* Keyword.Pseudo */ +.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.kt { color: #B00040 } /* Keyword.Type */ +.m { color: #666666 } /* Literal.Number */ +.s { color: #BA2121 } /* Literal.String */ +.na { color: #7D9029 } /* Name.Attribute */ +.nb { color: #008000 } /* Name.Builtin */ +.nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.no { color: #880000 } /* Name.Constant */ +.nd { color: #AA22FF } /* Name.Decorator */ +.ni { color: #999999; font-weight: bold } /* Name.Entity */ +.ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.nf { color: #0000FF } /* Name.Function */ +.nl { color: #A0A000 } /* Name.Label */ +.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.nt { color: #008000; font-weight: bold } /* Name.Tag */ +.nv { color: #19177C } /* Name.Variable */ +.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.w { color: #bbbbbb } /* Text.Whitespace */ +.mb { color: #666666 } /* Literal.Number.Bin */ +.mf { color: #666666 } /* Literal.Number.Float */ +.mh { color: #666666 } /* Literal.Number.Hex */ +.mi { color: #666666 } /* Literal.Number.Integer */ +.mo { color: #666666 } /* Literal.Number.Oct */ +.sa { color: #BA2121 } /* Literal.String.Affix */ +.sb { color: #BA2121 } /* Literal.String.Backtick */ +.sc { color: #BA2121 } /* Literal.String.Char */ +.dl { color: #BA2121 } /* Literal.String.Delimiter */ +.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.s2 { color: #BA2121 } /* Literal.String.Double */ +.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.sh { color: #BA2121 } /* Literal.String.Heredoc */ +.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.sx { color: #008000 } /* Literal.String.Other */ +.sr { color: #BB6688 } /* Literal.String.Regex */ +.s1 { color: #BA2121 } /* Literal.String.Single */ +.ss { color: #19177C } /* Literal.String.Symbol */ +.bp { color: #008000 } /* Name.Builtin.Pseudo */ +.fm { color: #0000FF } /* Name.Function.Magic */ +.vc { color: #19177C } /* Name.Variable.Class */ +.vg { color: #19177C } /* Name.Variable.Global */ +.vi { color: #19177C } /* Name.Variable.Instance */ +.vm { color: #19177C } /* Name.Variable.Magic */ +.il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/apidoc/html/up-insensitive.png b/apidoc/html/up-insensitive.png new file mode 100644 index 0000000..f404986 Binary files /dev/null and b/apidoc/html/up-insensitive.png differ diff --git a/apidoc/html/up.png b/apidoc/html/up.png new file mode 100644 index 0000000..80b4b37 Binary files /dev/null and b/apidoc/html/up.png differ diff --git a/apidoc/ostree-docs.xml b/apidoc/ostree-docs.xml new file mode 100644 index 0000000..1ad0de3 --- /dev/null +++ b/apidoc/ostree-docs.xml @@ -0,0 +1,36 @@ + + + +]> + + + OSTree API references + for OSTree &version; + + + + API Reference + + + + + + + + + + + + + + + + + API Index + + + + diff --git a/apidoc/ostree-experimental-sections.txt b/apidoc/ostree-experimental-sections.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/apidoc/ostree-experimental-sections.txt diff --git a/apidoc/ostree-overrides.txt b/apidoc/ostree-overrides.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/apidoc/ostree-overrides.txt diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt new file mode 100644 index 0000000..979c8e9 --- /dev/null +++ b/apidoc/ostree-sections.txt @@ -0,0 +1,729 @@ +
+ostree-async-progress +OstreeAsyncProgress +ostree_async_progress_new +ostree_async_progress_new_and_connect +ostree_async_progress_copy_state +ostree_async_progress_get_status +ostree_async_progress_get +ostree_async_progress_get_variant +ostree_async_progress_get_uint +ostree_async_progress_get_uint64 +ostree_async_progress_set_status +ostree_async_progress_set +ostree_async_progress_set_variant +ostree_async_progress_set_uint +ostree_async_progress_set_uint64 +ostree_async_progress_finish + +OSTREE_ASYNC_PROGRESS +OSTREE_IS_ASYNC_PROGRESS +OSTREE_TYPE_ASYNC_PROGRESS +OSTREE_ASYNC_PROGRESS_CLASS +OSTREE_IS_ASYNC_PROGRESS_CLASS +OSTREE_ASYNC_PROGRESS_GET_CLASS +OstreeAsyncProgressClass +ostree_async_progress_get_type +
+ +
+ostree-bootconfig-parser +OstreeBootconfigParser +ostree_bootconfig_parser_new +ostree_bootconfig_parser_clone +ostree_bootconfig_parser_parse +ostree_bootconfig_parser_parse_at +ostree_bootconfig_parser_write +ostree_bootconfig_parser_write_at +ostree_bootconfig_parser_set +ostree_bootconfig_parser_get + +OSTREE_BOOTCONFIG_PARSER +OSTREE_IS_BOOTCONFIG_PARSER +OSTREE_TYPE_BOOTCONFIG_PARSER +ostree_bootconfig_parser_get_type +
+ +
+ostree-chain-input-stream +OstreeChainInputStream +ostree_chain_input_stream_new + +OSTREE_CHAIN_INPUT_STREAM +OSTREE_IS_CHAIN_INPUT_STREAM +OSTREE_TYPE_CHAIN_INPUT_STREAM +OSTREE_CHAIN_INPUT_STREAM_CLASS +OSTREE_IS_CHAIN_INPUT_STREAM_CLASS +OSTREE_CHAIN_INPUT_STREAM_GET_CLASS +OstreeChainInputStreamClass +OstreeChainInputStreamPrivate +ostree_chain_input_stream_get_type +
+ +
+ostree-checksum-input-stream +OstreeChecksumInputStream +ostree_checksum_input_stream_new + +OSTREE_CHECKSUM_INPUT_STREAM +OSTREE_IS_CHECKSUM_INPUT_STREAM +OSTREE_TYPE_CHECKSUM_INPUT_STREAM +OSTREE_CHECKSUM_INPUT_STREAM_CLASS +OSTREE_IS_CHECKSUM_INPUT_STREAM_CLASS +OSTREE_CHECKSUM_INPUT_STREAM_GET_CLASS +OstreeChecksumInputStreamClass +OstreeChecksumInputStreamPrivate +ostree_checksum_input_stream_get_type +
+ +
+ostree-version +OSTREE_CHECK_VERSION +OSTREE_YEAR_VERSION +OSTREE_RELEASE_VERSION +OSTREE_VERSION +OSTREE_VERSION_S +OSTREE_VERSION_HEX +
+ +
+ostree-core +OSTREE_MAX_METADATA_SIZE +OSTREE_MAX_METADATA_WARN_SIZE +OstreeObjectType +OSTREE_OBJECT_TYPE_IS_META +OSTREE_OBJECT_TYPE_LAST +OSTREE_DIRMETA_GVARIANT_STRING +OSTREE_DIRMETA_GVARIANT_FORMAT +OSTREE_FILEMETA_GVARIANT_STRING +OSTREE_FILEMETA_GVARIANT_FORMAT +OSTREE_TREE_GVARIANT_STRING +OSTREE_TREE_GVARIANT_FORMAT +OSTREE_COMMIT_GVARIANT_STRING +OSTREE_COMMIT_GVARIANT_FORMAT +OSTREE_SUMMARY_GVARIANT_STRING +OSTREE_SUMMARY_GVARIANT_FORMAT +ostree_metadata_variant_type +ostree_validate_checksum_string +ostree_checksum_to_bytes +ostree_checksum_to_bytes_v +ostree_checksum_from_bytes +ostree_checksum_from_bytes_v +ostree_checksum_inplace_from_bytes +ostree_checksum_inplace_to_bytes +ostree_checksum_bytes_peek +ostree_checksum_bytes_peek_validate +ostree_checksum_b64_from_bytes +ostree_checksum_b64_to_bytes +ostree_checksum_b64_inplace_from_bytes +ostree_checksum_b64_inplace_to_bytes +ostree_cmp_checksum_bytes +ostree_validate_rev +ostree_validate_remote_name +ostree_parse_refspec +ostree_object_type_to_string +ostree_object_type_from_string +ostree_hash_object_name +ostree_object_name_serialize +ostree_object_name_deserialize +ostree_object_to_string +ostree_object_from_string +ostree_content_stream_parse +ostree_content_file_parse +ostree_content_file_parse_at +ostree_raw_file_to_archive_z2_stream +ostree_raw_file_to_archive_z2_stream_with_options +ostree_raw_file_to_content_stream +ostree_break_hardlink +ostree_checksum_file_from_input +ostree_checksum_file +ostree_checksum_file_at +ostree_checksum_file_async +ostree_checksum_file_async_finish +ostree_create_directory_metadata +ostree_validate_structureof_objtype +ostree_validate_structureof_csum_v +ostree_validate_structureof_checksum_string +ostree_validate_structureof_file_mode +ostree_validate_structureof_commit +ostree_validate_structureof_dirtree +ostree_validate_structureof_dirmeta +ostree_commit_get_parent +ostree_commit_get_timestamp +ostree_commit_get_content_checksum +ostree_commit_get_object_sizes +OstreeCommitSizesEntry +ostree_commit_sizes_entry_new +ostree_commit_sizes_entry_copy +ostree_commit_sizes_entry_free +ostree_check_version + +ostree_commit_sizes_entry_get_type +
+ +
+ostree-deployment +OstreeDeployment +ostree_deployment_hash +ostree_deployment_equal +ostree_deployment_new +ostree_deployment_get_index +ostree_deployment_get_osname +ostree_deployment_get_deployserial +ostree_deployment_get_csum +ostree_deployment_get_bootcsum +ostree_deployment_get_bootserial +ostree_deployment_get_bootconfig +ostree_deployment_get_origin +ostree_deployment_get_origin_relpath +ostree_deployment_get_unlocked +ostree_deployment_is_pinned +ostree_deployment_is_staged +ostree_deployment_set_index +ostree_deployment_set_bootserial +ostree_deployment_set_bootconfig +ostree_deployment_set_origin +ostree_deployment_origin_remove_transient_state +ostree_deployment_clone +ostree_deployment_unlocked_state_to_string + +OSTREE_DEPLOYMENT +OSTREE_IS_DEPLOYMENT +OSTREE_TYPE_DEPLOYMENT +ostree_deployment_get_type +
+ +
+ostree-diff +OstreeDiffFlags +OstreeDiffItem +ostree_diff_item_ref +ostree_diff_item_unref +ostree_diff_dirs +ostree_diff_dirs_with_options +ostree_diff_print + +ostree_diff_item_get_type +
+ +
+ostree-gpg-verify-result +OstreeGpgError +OstreeGpgVerifyResult +OstreeGpgSignatureAttr +ostree_gpg_verify_result_count_all +ostree_gpg_verify_result_count_valid +ostree_gpg_verify_result_lookup +ostree_gpg_verify_result_get +ostree_gpg_verify_result_get_all +OstreeGpgSignatureFormatFlags +ostree_gpg_verify_result_describe +ostree_gpg_verify_result_describe_variant +ostree_gpg_verify_result_require_valid_signature + +OSTREE_GPG_VERIFY_RESULT +OSTREE_IS_GPG_VERIFY_RESULT +OSTREE_TYPE_GPG_VERIFY_RESULT +ostree_gpg_verify_result_get_type +OSTREE_GPG_ERROR +ostree_gpg_error_quark +
+ +ostree-lzma-compressor + +OSTREE_IS_LZMA_COMPRESSOR +OSTREE_IS_LZMA_COMPRESSOR_CLASS +OSTREE_LZMA_COMPRESSOR +OSTREE_LZMA_COMPRESSOR_CLASS +OSTREE_LZMA_COMPRESSOR_GET_CLASS +OSTREE_TYPE_LZMA_COMPRESSOR +OstreeLzmaCompressor +OstreeLzmaCompressorClass + + +
+ostree-lzma-decompressor + +OSTREE_IS_LZMA_DECOMPRESSOR +OSTREE_IS_LZMA_DECOMPRESSOR_CLASS +OSTREE_LZMA_DECOMPRESSOR +OSTREE_LZMA_DECOMPRESSOR_CLASS +OSTREE_LZMA_DECOMPRESSOR_GET_CLASS +OSTREE_TYPE_LZMA_DECOMPRESSOR +OstreeLzmaDecompressor +OstreeLzmaDecompressorClass +
+ +
+ostree-mutable-tree +OstreeMutableTree +ostree_mutable_tree_new +ostree_mutable_tree_new_from_checksum +ostree_mutable_tree_check_error +ostree_mutable_tree_set_metadata_checksum +ostree_mutable_tree_get_metadata_checksum +ostree_mutable_tree_set_contents_checksum +ostree_mutable_tree_get_contents_checksum +ostree_mutable_tree_replace_file +ostree_mutable_tree_remove +ostree_mutable_tree_ensure_dir +ostree_mutable_tree_lookup +ostree_mutable_tree_ensure_parent_dirs +ostree_mutable_tree_walk +ostree_mutable_tree_get_subdirs +ostree_mutable_tree_get_files +ostree_mutable_tree_fill_empty_from_dirtree + +OSTREE_MUTABLE_TREE +OSTREE_IS_MUTABLE_TREE +OSTREE_TYPE_MUTABLE_TREE +OSTREE_MUTABLE_TREE_CLASS +OSTREE_IS_MUTABLE_TREE_CLASS +OSTREE_MUTABLE_TREE_GET_CLASS +OstreeMutableTreeClass +ostree_mutable_tree_get_type +
+ +
+ostree-repo +OstreeRepo +OstreeRepo +OstreeRepoMode +ostree_repo_mode_from_string +ostree_repo_open_at +ostree_repo_new +ostree_repo_new_for_sysroot_path +ostree_repo_new_default +ostree_repo_open +ostree_repo_set_disable_fsync +ostree_repo_get_disable_fsync +ostree_repo_is_system +ostree_repo_is_writable +ostree_repo_create_at +ostree_repo_create +ostree_repo_get_bootloader +ostree_repo_get_path +ostree_repo_get_mode +ostree_repo_get_min_free_space_bytes +ostree_repo_get_config +ostree_repo_get_dfd +ostree_repo_get_default_repo_finders +ostree_repo_hash +ostree_repo_equal +ostree_repo_copy_config +ostree_repo_remote_add +ostree_repo_remote_delete +OstreeRepoRemoteChange +ostree_repo_remote_change +ostree_repo_remote_list +ostree_repo_remote_get_url +ostree_repo_remote_get_gpg_verify +ostree_repo_remote_get_gpg_verify_summary +ostree_repo_remote_gpg_import +ostree_repo_remote_fetch_summary +ostree_repo_remote_fetch_summary_with_options +ostree_repo_reload_config +ostree_repo_get_remote_boolean_option +ostree_repo_get_remote_list_option +ostree_repo_get_remote_option +ostree_repo_get_parent +ostree_repo_write_config +OstreeRepoTransactionStats +ostree_repo_scan_hardlinks +ostree_repo_prepare_transaction +ostree_repo_commit_transaction +ostree_repo_abort_transaction +ostree_repo_transaction_set_refspec +ostree_repo_transaction_set_ref +ostree_repo_set_ref_immediate +ostree_repo_set_alias_ref_immediate +ostree_repo_set_cache_dir +ostree_repo_sign_delta +ostree_repo_has_object +ostree_repo_mark_commit_partial +ostree_repo_mark_commit_partial_reason +ostree_repo_write_metadata +ostree_repo_write_metadata_async +ostree_repo_write_metadata_finish +ostree_repo_write_content +ostree_repo_write_metadata_trusted +ostree_repo_write_metadata_stream_trusted +ostree_repo_write_content_trusted +ostree_repo_write_content_async +ostree_repo_write_content_finish +ostree_repo_resolve_rev +OstreeRepoResolveRevExtFlags +ostree_repo_resolve_rev_ext +ostree_repo_list_refs +OstreeRepoListRefsExtFlags +ostree_repo_list_refs_ext +ostree_repo_remote_list_refs +ostree_repo_load_variant +OstreeRepoCommitState +ostree_repo_load_commit +ostree_repo_load_variant_if_exists +ostree_repo_load_file +ostree_repo_load_object_stream +ostree_repo_query_object_storage_size +ostree_repo_import_object_from +ostree_repo_import_object_from_with_trust +ostree_repo_import_archive_to_mtree +ostree_repo_export_tree_to_archive +ostree_repo_delete_object +ostree_repo_fsck_object +OstreeRepoCommitFilterResult +OstreeRepoCommitFilter +OstreeRepoCommitModifier +OstreeRepoCommitModifierFlags +ostree_repo_commit_modifier_new +OstreeRepoCommitModifierXattrCallback +ostree_repo_commit_modifier_set_xattr_callback +ostree_repo_commit_modifier_set_sepolicy +ostree_repo_commit_modifier_set_sepolicy_from_commit +ostree_repo_commit_modifier_set_devino_cache +ostree_repo_commit_modifier_ref +ostree_repo_commit_modifier_unref +ostree_repo_devino_cache_new +ostree_repo_devino_cache_ref +ostree_repo_devino_cache_unref +ostree_repo_devino_cache_get_type +ostree_repo_write_directory_to_mtree +ostree_repo_write_dfd_to_mtree +ostree_repo_write_archive_to_mtree +ostree_repo_write_archive_to_mtree_from_fd +ostree_repo_write_mtree +ostree_repo_write_commit +ostree_repo_write_commit_with_time +ostree_repo_read_commit_detached_metadata +ostree_repo_write_commit_detached_metadata +OstreeRepoCheckoutAtOptions +ostree_repo_checkout_at_options_set_devino +OstreeRepoCheckoutMode +OstreeRepoCheckoutOverwriteMode +ostree_repo_checkout_tree +ostree_repo_checkout_tree_at +ostree_repo_checkout_at +ostree_repo_checkout_gc +ostree_repo_read_commit +OstreeRepoListObjectsFlags +OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE +ostree_repo_list_objects +ostree_repo_list_commit_objects_starting_with +ostree_repo_list_static_delta_names +OstreeStaticDeltaGenerateOpt +ostree_repo_static_delta_generate +ostree_repo_static_delta_execute_offline +ostree_repo_traverse_new_reachable +ostree_repo_traverse_new_parents +ostree_repo_traverse_parents_get_commits +ostree_repo_traverse_commit +ostree_repo_traverse_commit_union +ostree_repo_traverse_commit_union_with_parents +ostree_repo_commit_traverse_iter_cleanup +ostree_repo_commit_traverse_iter_clear +ostree_repo_commit_traverse_iter_get_dir +ostree_repo_commit_traverse_iter_get_file +OstreeRepoCommitTraverseFlags +ostree_repo_commit_traverse_iter_init_commit +ostree_repo_commit_traverse_iter_init_dirtree +OstreeRepoCommitIterResult +ostree_repo_commit_traverse_iter_next +OstreeRepoPruneFlags +ostree_repo_prune +ostree_repo_prune_static_deltas +ostree_repo_traverse_reachable_refs +ostree_repo_prune_from_reachable +OstreeRepoPullFlags +ostree_repo_pull +ostree_repo_pull_one_dir +ostree_repo_pull_with_options +ostree_repo_pull_default_console_progress_changed +ostree_repo_sign_commit +ostree_repo_append_gpg_signature +ostree_repo_add_gpg_signature_summary +ostree_repo_gpg_verify_data +ostree_repo_verify_commit +ostree_repo_verify_commit_ext +ostree_repo_verify_commit_for_remote +ostree_repo_verify_summary +ostree_repo_regenerate_summary + +OSTREE_REPO +OSTREE_IS_REPO +OSTREE_TYPE_REPO +ostree_repo_get_type +ostree_repo_commit_modifier_get_type +ostree_repo_transaction_stats_get_type +
+ +
+ostree-repo-file +OstreeRepoFile +ostree_repo_file_ensure_resolved +ostree_repo_file_get_xattrs +ostree_repo_file_get_repo +ostree_repo_file_get_root +ostree_repo_file_tree_set_metadata +ostree_repo_file_tree_get_contents_checksum +ostree_repo_file_tree_get_metadata_checksum +ostree_repo_file_tree_get_contents +ostree_repo_file_tree_get_metadata +ostree_repo_file_get_checksum +ostree_repo_file_tree_find_child +ostree_repo_file_tree_query_child + +OSTREE_REPO_FILE +OSTREE_IS_REPO_FILE +OSTREE_TYPE_REPO_FILE +OSTREE_REPO_FILE_CLASS +OSTREE_IS_REPO_FILE_CLASS +OSTREE_REPO_FILE_GET_CLASS +OstreeRepoFileClass +ostree_repo_file_get_type +
+ +
+ostree-sepolicy +OstreeSePolicy +ostree_sepolicy_new +ostree_sepolicy_new_at +ostree_sepolicy_get_path +ostree_sepolicy_get_name +ostree_sepolicy_get_label +ostree_sepolicy_get_csum +OstreeSePolicyRestoreconFlags +ostree_sepolicy_restorecon +ostree_sepolicy_setfscreatecon +ostree_sepolicy_fscreatecon_cleanup + +OSTREE_SEPOLICY +OSTREE_IS_SEPOLICY +OSTREE_TYPE_SEPOLICY +ostree_sepolicy_get_type +
+ +
+ostree-sysroot +OstreeSysroot +ostree_sysroot_new +ostree_sysroot_new_default +ostree_sysroot_initialize +ostree_sysroot_get_path +ostree_sysroot_load +ostree_sysroot_load_if_changed +ostree_sysroot_lock +ostree_sysroot_try_lock +ostree_sysroot_lock_async +ostree_sysroot_lock_finish +ostree_sysroot_unlock +ostree_sysroot_unload +ostree_sysroot_set_mount_namespace_in_use +ostree_sysroot_is_booted +ostree_sysroot_get_fd +ostree_sysroot_ensure_initialized +ostree_sysroot_get_bootversion +ostree_sysroot_get_subbootversion +ostree_sysroot_get_deployments +ostree_sysroot_get_booted_deployment +ostree_sysroot_get_deployment_directory +ostree_sysroot_get_deployment_dirpath +ostree_sysroot_get_deployment_origin_path +ostree_sysroot_cleanup +ostree_sysroot_prepare_cleanup +ostree_sysroot_cleanup_prune_repo +ostree_sysroot_repo +ostree_sysroot_get_repo +ostree_sysroot_get_staged_deployment +ostree_sysroot_init_osname +ostree_sysroot_deployment_set_kargs +ostree_sysroot_deployment_set_mutable +ostree_sysroot_deployment_unlock +ostree_sysroot_deployment_set_pinned +ostree_sysroot_write_deployments +ostree_sysroot_write_deployments_with_options +ostree_sysroot_write_origin_file +ostree_sysroot_stage_tree +ostree_sysroot_deploy_tree +ostree_sysroot_get_merge_deployment +ostree_sysroot_query_deployments_for +ostree_sysroot_origin_new_from_refspec +OstreeSysrootSimpleWriteDeploymentFlags +ostree_sysroot_simple_write_deployment + +OSTREE_SYSROOT +OSTREE_IS_SYSROOT +OSTREE_TYPE_SYSROOT +ostree_sysroot_get_type +
+ +
+ostree-sysroot-upgrader +OstreeSysrootUpgrader +ostree_sysroot_upgrader_new +ostree_sysroot_upgrader_new_for_os +OstreeSysrootUpgraderFlags +ostree_sysroot_upgrader_new_for_os_with_flags +ostree_sysroot_upgrader_get_origin +ostree_sysroot_upgrader_dup_origin +ostree_sysroot_upgrader_set_origin +ostree_sysroot_upgrader_get_origin_description +ostree_sysroot_upgrader_check_timestamps +OstreeSysrootUpgraderPullFlags +ostree_sysroot_upgrader_pull +ostree_sysroot_upgrader_pull_one_dir +ostree_sysroot_upgrader_deploy + +OSTREE_SYSROOT_UPGRADER +OSTREE_IS_SYSROOT_UPGRADER +OSTREE_TYPE_SYSROOT_UPGRADER +ostree_sysroot_upgrader_get_type +ostree_sysroot_upgrader_flags_get_type +
+ +
+ostree-ref +OstreeCollectionRef +ostree_collection_ref_new +ostree_collection_ref_dup +ostree_collection_ref_free +ostree_collection_ref_hash +ostree_collection_ref_equal +OstreeCollectionRefv +ostree_collection_ref_dupv +ostree_collection_ref_freev + +ostree_collection_ref_get_type +
+ +
+ostree-remote +OstreeRemote +ostree_remote_ref +ostree_remote_unref +ostree_remote_get_name +ostree_remote_get_url + +ostree_remote_get_type +
+ +
+ostree-repo-experimental +ostree_repo_find_remotes_async +ostree_repo_find_remotes_finish +ostree_repo_pull_from_remotes_async +ostree_repo_pull_from_remotes_finish +ostree_repo_resolve_keyring_for_collection +OSTREE_REPO_METADATA_REF +OSTREE_META_KEY_DEPLOY_COLLECTION_ID +
+ +
+ostree-repo-finder +OstreeRepoFinder +ostree_repo_finder_resolve_async +ostree_repo_finder_resolve_finish +ostree_repo_finder_resolve_all_async +ostree_repo_finder_resolve_all_finish +OstreeRepoFinderResult +ostree_repo_finder_result_new +ostree_repo_finder_result_dup +ostree_repo_finder_result_free +ostree_repo_finder_result_compare +OstreeRepoFinderResultv +ostree_repo_finder_result_freev + +ostree_repo_finder_get_type +ostree_repo_finder_result_get_type +
+ +
+ostree-repo-finder-avahi +OstreeRepoFinderAvahi +ostree_repo_finder_avahi_new +ostree_repo_finder_avahi_start +ostree_repo_finder_avahi_stop + +ostree_repo_finder_avahi_get_type +
+ +
+ostree-repo-finder-config +OstreeRepoFinderConfig +ostree_repo_finder_config_new + +ostree_repo_finder_config_get_type +
+ +
+ostree-repo-finder-mount +OstreeRepoFinderMount +ostree_repo_finder_mount_new + +ostree_repo_finder_mount_get_type +
+ +
+ostree-repo-finder-override +OstreeRepoFinderOverride +ostree_repo_finder_override_new +ostree_repo_finder_override_add_uri + +ostree_repo_finder_override_get_type +
+ +
+ostree-misc-experimental +ostree_repo_get_collection_id +ostree_repo_set_collection_id +ostree_validate_collection_id +ostree_repo_list_collection_refs +ostree_repo_remote_list_collection_refs +ostree_repo_set_collection_ref_immediate +ostree_repo_transaction_set_collection_ref +ostree_repo_resolve_collection_ref +
+ +
+ostree-kernel-args +OstreeKernelArgs +ostree_kernel_args_free +ostree_kernel_args_new +ostree_kernel_args_cleanup +ostree_kernel_args_replace_take +ostree_kernel_args_replace +ostree_kernel_args_replace_argv +ostree_kernel_args_append +ostree_kernel_args_append_argv +ostree_kernel_args_append_argv_filtered +ostree_kernel_args_new_replace +ostree_kernel_args_delete +ostree_kernel_args_delete_key_entry +ostree_kernel_args_append_proc_cmdline +ostree_kernel_args_parse_append +ostree_kernel_args_get_last_value +ostree_kernel_args_from_string +ostree_kernel_args_to_strv +ostree_kernel_args_to_string +
+ +
+ostree-sign +OstreeSign +ostree_sign_get_all +ostree_sign_commit +ostree_sign_commit_verify +ostree_sign_data +ostree_sign_data_verify +ostree_sign_get_by_name +ostree_sign_get_name +ostree_sign_add_pk +ostree_sign_clear_keys +ostree_sign_load_pk +ostree_sign_metadata_format +ostree_sign_metadata_key +ostree_sign_set_pk +ostree_sign_set_sk +ostree_sign_summary + +ostree_sign_get_type +
diff --git a/apidoc/ostree.types b/apidoc/ostree.types new file mode 100644 index 0000000..d9a4dbf --- /dev/null +++ b/apidoc/ostree.types @@ -0,0 +1,28 @@ +ostree_async_progress_get_type +ostree_bloom_get_type +ostree_bootconfig_parser_get_type +ostree_chain_input_stream_get_type +ostree_checksum_input_stream_get_type +ostree_collection_ref_get_type +ostree_commit_sizes_entry_get_type +ostree_deployment_get_type +ostree_diff_item_get_type +ostree_gpg_verify_result_get_type +ostree_mutable_tree_get_type +ostree_remote_get_type +ostree_repo_commit_modifier_get_type +ostree_repo_devino_cache_get_type +ostree_repo_file_get_type +ostree_repo_finder_avahi_get_type +ostree_repo_finder_config_get_type +ostree_repo_finder_get_type +ostree_repo_finder_mount_get_type +ostree_repo_finder_override_get_type +ostree_repo_finder_result_get_type +ostree_repo_get_type +ostree_repo_transaction_stats_get_type +ostree_sepolicy_get_type +ostree_sign_get_type +ostree_sysroot_get_type +ostree_sysroot_upgrader_flags_get_type +ostree_sysroot_upgrader_get_type diff --git a/apidoc/version.xml b/apidoc/version.xml new file mode 100644 index 0000000..a771cf0 --- /dev/null +++ b/apidoc/version.xml @@ -0,0 +1 @@ +2020.4 \ No newline at end of file diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..689bba8 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. + +olddir=`pwd` +cd $srcdir + +AUTORECONF=`which autoreconf` +if test -z $AUTORECONF; then + echo "*** No autoreconf found, please install it ***" + exit 1 +fi + +set -e + +mkdir -p m4 + +GTKDOCIZE=$(which gtkdocize 2>/dev/null || true) +if test -z "$GTKDOCIZE"; then + echo "You don't have gtk-doc installed, and thus won't be able to generate the documentation." + rm -f gtk-doc.make + cat > gtk-doc.make <libglnx/Makefile-libglnx.am.inc +sed -e 's,$(libbsdiff_srcpath),bsdiff,g' < bsdiff/Makefile-bsdiff.am >bsdiff/Makefile-bsdiff.am.inc + +# FIXME - figure out how to get aclocal to find this by default +ln -sf ../libglnx/libglnx.m4 buildutil/libglnx.m4 + +autoreconf --force --install --verbose + +cd $olddir +test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/bash/ostree b/bash/ostree new file mode 100644 index 0000000..7256e40 --- /dev/null +++ b/bash/ostree @@ -0,0 +1,1860 @@ +# bash completion file for ostree commands +# +# This script provides completion of: +# - commands and their options +# - ostree commit checksums +# - ostree ref names +# +# To enable the completions either: +# - place this file in /etc/bash_completion.d +# or +# - copy this file to e.g. ~/.ostree-completion.sh and add the line +# below to your .bashrc after bash completion features are loaded +# . ~/.ostree-completion.sh +# +# Note for developers: +# Please arrange options sorted alphabetically by long name with the short +# options immediately following their corresponding long form. +# This order should be applied to lists, alternatives and code blocks. + +# TODO +# +# - Long form options with an equal sign (--foo=BAR) are not parsed. +# +# - Structured option arguments (e.g. --foo KEY=VALUE) are not parsed. +# +# - Static deltas could likely be completed. (e.g. ostree static-delta delete [TAB]) + + +# Finds the position of the first non-flag word. +__ostree_pos_first_nonflag() { + local argument_flags=$1 + + local counter=$cpos + while [ $counter -le $cword ]; do + if [ -n "$argument_flags" ] && eval "case '${words[$counter]}' in $argument_flags) true ;; *) false ;; esac"; then + (( counter++ )) + else + case "${words[$counter]}" in + -*) + ;; + *) + break + ;; + esac + fi + (( counter++ )) + done + + echo $counter +} + +# Transforms a multiline list of strings into a single line string +# with the words separated by "|". +# This is used to prepare arguments to __ostree_pos_first_nonflag(). +__ostree_to_alternatives() { + local parts=( $1 ) + local IFS='|' + echo "${parts[*]}" +} + +# Transforms a multiline list of options into an extglob pattern +# suitable for use in case statements. +__ostree_to_extglob() { + local extglob=$( __ostree_to_alternatives "$1" ) + echo "@($extglob)" +} + +# Transform object path to a 64-char checksum. +__ostree_object_to_checksum() { + local str=( $1 ) + # Trim off extension (e.g. .commit) + str=${str%.*} + # Isolate checksum portion (nn/nnn...) + str=${str: -65} + # Drop the slash + echo "${str/\//}" +} + +__ostree_compreply_all_options() { + COMPREPLY+=( $( compgen -W "$all_options" -- "$cur" ) ) +} + +__ostree_compreply_all_files() { + compopt -o nospace + COMPREPLY+=( $( compgen -f "$cur" ) ) +} + +__ostree_compreply_dirs_only() { + compopt -o nospace + COMPREPLY+=( $( compgen -d "$cur" ) ) +} + +# Find commit objects under $repo_path. +__ostree_compreply_commits() { + local objectsdir="$repo_path/objects" + if test -d "$objectsdir"; then + local commits=() + for path in `find "$objectsdir" -name "*.commit"`; do + commits+=( $( __ostree_object_to_checksum "$path" ) ) + done + COMPREPLY+=( $( compgen -W "$commits" -- "$cur" ) ) + fi +} + +# Find oses under $sysroot_path +__ostree_compreply_oses() { + local deploydir="$sysroot_path/ostree/deploy" + if test -d "$deploydir"; then + local oses=() + for path in `find "$deploydir" -mindepth 1 -maxdepth 1 -type d`; do + oses+=( $( basename "$path" ) ) + done + COMPREPLY+=( $( compgen -W "$oses" -- "$cur" ) ) + fi +} + +# Find refs associated with the given collection ID under $repo_path. +__ostree_compreply_collection_refs() { + local collection_id=( $1 ) + refs=$( ostree refs --repo $repo_path --collections $collection_id 2>/dev/null | cut -d ' ' -f 2 | sed -e 's/)$//' ) + COMPREPLY+=( $( compgen -W "$refs" -- "$cur" ) ) +} + +# Find refs under $repo_path. +__ostree_compreply_refs() { + refs=$( ostree refs --repo $repo_path 2>/dev/null ) + COMPREPLY+=( $( compgen -W "$refs" -- "$cur" ) ) +} + +# Find collection IDs under $repo_path. +__ostree_compreply_collection_ids() { + collection_ids=$( ostree refs --repo $repo_path --collections 2>/dev/null | cut -d ',' -f 1 | sed -e 's/^(//' | sort | uniq ) + COMPREPLY+=( $( compgen -W "$collection_ids" -- "$cur" ) ) +} + +# Find remotes under $repo_path. +__ostree_compreply_remotes() { + remotes=$( ostree remote list --repo $repo_path 2> /dev/null ) + COMPREPLY+=( $( compgen -W "$remotes" -- "$cur" ) ) +} + +# Find commit objects and refs under $repo_path. +__ostree_compreply_revisions() { + __ostree_compreply_commits + __ostree_compreply_refs +} + +# Subcommand processing. +# Locates the first occurrence of any of the subcommands contained in the +# first argument. In case of a match, calls the corresponding completion +# function and returns 0. +# If no match is found, 1 is returned. The calling function can then +# continue processing its completion. +# +# TODO If the preceding command has options that accept arguments and an +# argument is equal to one of the subcommands, this is falsely detected +# as a match. +__ostree_subcommands() { + local subcommands="$1" + + local counter=$cpos + while [ $counter -lt $cword ]; do + case "${words[$counter]}" in + $( __ostree_to_extglob "$subcommands" ) ) + local subcommand=${words[$counter]} + cpos=$counter + (( cpos++ )) + local completions_func=_ostree_${command//-/_}_${subcommand//-/_} + declare -F $completions_func >/dev/null && $completions_func + return 0 + ;; + esac + (( counter++ )) + done + return 1 +} + +# This handles "ostree [TAB]" (without a subcommand). +_ostree_ostree() { + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$main_options" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$commands" -- "$cur" ) ) + ;; + esac + + return 0 +} + +_ostree_cat() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + elif [ $cword -eq $(($argpos + 1)) ]; then + __ostree_compreply_dirs_only + fi + ;; + esac + + return 0 +} + +_ostree_checkout() { + local boolean_options=" + $main_boolean_options + --allow-noent + --bareuseronly-dirs -M + --disable-cache + --force-copy -C + --from-stdin + --require-hardlinks -H + --union + --union-add + --union-identical + --user-mode -U + --whiteouts + " + + local options_with_args=" + --from-file + --fsync + --repo + --subpath + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --from-file) + __ostree_compreply_all_files + return 0 + ;; + --repo|--subpath) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + elif [ $cword -eq $(($argpos + 1)) ]; then + __ostree_compreply_dirs_only + fi + esac + + return 0 +} + +_ostree_checksum() { + local boolean_options=" + $main_boolean_options + --ignore-xattrs + " + + case "$cur" in + -*) + local all_options="$boolean_options" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "") ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_all_files + fi + ;; + esac + + return 0 +} + +_ostree_commit() { + local boolean_options=" + $main_boolean_options + --canonical-permissions + --editor -e + --generate-sizes + --link-checkout-speedup + --no-xattrs + --orphan + --consume + --skip-if-unchanged + --table-output + --tar-autocreate-parents + " + + local options_with_args=" + --add-detached-metadata-string + --add-metadata-string + --add-metadata + --keep-metadata + --bind-ref + --body -m + --body-file -F + --branch -b + --fsync + --gpg-homedir + --gpg-sign + --owner-gid + --owner-uid + --parent + --repo + --skip-list + --statoverride + --subject -s + --timestamp + --tree + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --body-file|--skip-list|--statoverride) + __ostree_compreply_all_files + return 0 + ;; + --gpg-homedir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + --bind-ref) + __ostree_compreply_refs + return 0 + ;; + --parent) + __ostree_compreply_commits + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_all_files + fi + esac + + return 0 +} + +_ostree_config() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --group + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_create_usb() { + local boolean_options=" + $main_boolean_options + --disable-fsync + " + + local options_with_args=" + --destination-repo + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --destination-repo|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_dirs_only + elif [ $cword -gt $argpos ] && [ $(((cword - argpos) % 2)) -eq 1 ]; then + __ostree_compreply_collection_ids + elif [ $cword -gt $argpos ] && [ $(((cword - argpos) % 2)) -eq 0 ]; then + __ostree_compreply_collection_refs "${words[$cword - 1]}" + fi + esac + + return 0 +} + +_ostree_diff() { + local boolean_options=" + $main_boolean_options + --fs-diff + --no-xattrs + --stats + " + + local options_with_args=" + --owner-gid + --owner-uid + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_revisions + elif [ $cword -eq $(($argpos + 1)) ]; then + __ostree_compreply_dirs_only + fi + esac + + return 0 +} + +_ostree_export() { + local boolean_options=" + $main_boolean_options + --no-xattrs + " + + local options_with_args=" + --output -o + --prefix + --repo + --subpath + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --prefix|--repo|--subpath) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + fi + esac + + return 0 +} + +_ostree_find_remotes() { + local boolean_options=" + $main_boolean_options + --disable-fsync + --pull + " + + local options_with_args=" + --finders + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --finders) + local choices="config lan mount" + local config_first="config,lan config,mount config,lan,mount config,mount,lan" + local lan_first="lan,config lan,mount lan,config,mount lan,mount,config" + local mount_first="mount,config mount,lan mount,lan,config mount,config,lan" + COMPREPLY+=( $( compgen -W "$choices $config_first $lan_first $mount_first" -- "$cur" ) ) + return 0 + ;; + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -ge $argpos ] && [ $(((cword - argpos) % 2)) -eq 0 ]; then + __ostree_compreply_collection_ids + elif [ $cword -ge $argpos ] && [ $(((cword - argpos) % 2)) -eq 1 ]; then + __ostree_compreply_collection_refs "${words[$cword - 1]}" + fi + esac + + return 0 +} + +_ostree_fsck() { + local boolean_options=" + $main_boolean_options + --add-tombstones + --delete + --quiet -q + --verify-bindings + --verify-back-refs + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_gpg_sign() { + local boolean_options=" + $main_boolean_options + --delete -d + " + + local options_with_args=" + --gpg-homedir + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --gpg-homedir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + fi + esac + + return 0 +} + +_ostree_init() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --collection-id + --mode + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --mode) + COMPREPLY=( $( compgen -W "bare archive-z2" -- "$cur" ) ) + return 0 + ;; + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_log() { + local boolean_options=" + $main_boolean_options + --raw + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_revisions + fi + esac + + return 0 +} + +_ostree_ls() { + local boolean_options=" + $main_boolean_options + --checksum -C + --dironly -d + --nul-filenames-only + --recursive -R + --xattrs -X + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_revisions + return 0 + fi + + __ostree_compreply_all_files + esac + + return 0 +} + +_ostree_prune() { + local boolean_options=" + $main_boolean_options + --no-prune + --refs-only + --static-deltas-only + " + + local options_with_args=" + --delete-commit + --depth + --keep-younger-than + --repo + --retain-branch-depth + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --delete-commit) + __ostree_compreply_commits + return 0 + ;; + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_pull_local() { + local boolean_options=" + $main_boolean_options + --bareuseronly-files + --disable-fsync + --gpg-verify + --gpg-verify-summary + --require-static-deltas + --untrusted + " + + local options_with_args=" + --depth + --remote + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --remote) + __ostree_compreply_remotes + return 0 + ;; + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_dirs_only + return 0 + fi + + __ostree_revisions + esac + + return 0 +} + +_ostree_pull() { + local boolean_options=" + $main_boolean_options + --commit-metadata-only + --cache-dir + --disable-fsync + --disable-static-deltas + --require-static-deltas + --mirror + --untrusted + --bareuseronly-files + --dry-run + " + + local options_with_args=" + --depth + --http-header + --localcache-repo -L + --network-retries + --repo + --subpath + --update-frequency + --url + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --localcache-repo|-L|--repo|--subpath) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_refs() { + local boolean_options=" + $main_boolean_options + --alias -A + --collections -c + --delete + --list + --force + " + + local options_with_args=" + --create + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_remote_add() { + local boolean_options=" + $main_boolean_options + --if-not-exists + --force + --no-gpg-verify + " + + local options_with_args=" + --collection-id + --contenturl + --gpg-import + --repo + --set + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo|--sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + --gpg-import) + __ostree_compreply_all_files + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_remote_add_cookie() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_delete() { + local boolean_options=" + $main_boolean_options + --if-exists + " + + local options_with_args=" + --repo + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo|--sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_delete_cookie() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_gpg_import() { + local boolean_options=" + $main_boolean_options + --stdin + " + + local options_with_args=" + --keyfile -k + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --keyfile|-k) + __ostree_compreply_all_files + return 0 + ;; + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_list() { + local boolean_options=" + $main_boolean_options + --show-urls -u + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_remote_list_cookies() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_refs() { + local boolean_options=" + $main_boolean_options + --cache-dir + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_show_url() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_summary() { + local boolean_options=" + $main_boolean_options + --cache-dir + --raw + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote() { + local subcommands=" + add + add-cookie + delete + delete-cookie + gpg-import + list + list-cookies + refs + show-url + summary + " + + __ostree_subcommands "$subcommands" && return 0 + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$main_boolean_options" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac + + return 0 +} + +_ostree_reset() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_refs + elif [ $cword -eq $(($argpos + 1)) ]; then + __ostree_compreply_commits + fi + esac + + return 0 +} + +_ostree_rev_parse() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_revisions + fi + esac + + return 0 +} + +_ostree_show() { + local boolean_options=" + $main_boolean_options + --print-related + --print-sizes + --raw + " + + local options_with_args=" + --gpg-homedir + --gpg-verify-remote + --print-detached-metadata-key + --print-metadata-key + --print-variant-type + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --gpg-homedir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + --gpg-verify-remote) + __ostree_compreply_remotes + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_sign() { + local boolean_options=" + $main_boolean_options + --delete -d + --verify -v + " + + local options_with_args=" + --sign-type + --keys-file + --keys-dir + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --keys-file|--keys-dir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + fi + esac + + return 0 +} + +_ostree_static_delta_apply_offline() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_all_files + fi + esac + + return 0 +} + +_ostree_static_delta_delete() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_static_delta_generate() { + local boolean_options=" + $main_boolean_options + --disable-bsdiff + --empty + --in-not-exists -n + --inline + --max-bsdiff-size + --max-chunk-size + --min-fallback-size + --swap-endianness + " + + local options_with_args=" + --filename + --from + --repo + --set-endianness + --to + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --filename|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + --from|--to) + __ostree_compreply_revisions + return 0 + ;; + --set-endianness) + COMPREPLY=( $( compgen -W "l B" -- "$cur" ) ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_static_delta_list() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_static_delta_show() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_static_delta() { + local subcommands=" + apply-offline + delete + generate + list + show + " + + __ostree_subcommands "$subcommands" && return 0 + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$main_boolean_options" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac + + return 0 +} + +_ostree_summary() { + local boolean_options=" + $main_boolean_options + --raw + --update -u + --view -v + " + + local options_with_args=" + --add-metadata -m + --gpg-homedir + --gpg-sign + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --gpg-homedir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree() { + local commands=" + admin + cat + checkout + checksum + commit + config + create-usb + diff + export + find-remotes + fsck + gpg-sign + init + log + ls + prune + pull-local + pull + refs + remote + reset + rev-parse + show + sign + static-delta + summary + " + + # These are always available. + local main_boolean_options=" + --help -h + --verbose -v + --version + " + local main_options_with_args=" + --repo + " + local main_options_with_args_glob=$( __ostree_to_extglob "$main_options_with_args" ) + local main_options=" + $main_boolean_options + $main_options_with_args + " + + COMPREPLY=() + local cur prev words cword + + _get_comp_words_by_ref cur prev words cword + + local command='ostree' cpos=0 + local counter + + local repo_path='/sysroot/ostree/repo' + local sysroot_path='/sysroot' + + # These options can affect argument completion. + # FIXME Only recognizes the form --foo BAR, not --foo=BAR. + counter=1 + while [ $counter -lt $cword ]; do + if test "${words[$counter - 1]}" = "--repo"; then + repo_path=${words[$counter]} + elif test "${words[$counter - 1]}" = "--sysroot"; then + sysroot_path=${words[$counter]} + repo_path="$sysroot_path/ostree/repo" + fi + (( counter++ )) + done + + counter=1 + while [ $counter -lt $cword ]; do + case "${words[$counter]}" in + $main_options_with_args_glob ) + (( counter++ )) + ;; + -*) + ;; + *) + command="${words[$counter]}" + cpos=$counter + (( cpos++ )) + break + ;; + esac + (( counter++ )) + done + + local completions_func=_ostree_${command//-/_} + declare -F $completions_func >/dev/null && $completions_func + + return 0 +} + +complete -F _ostree ostree diff --git a/bsdiff/LICENSE b/bsdiff/LICENSE new file mode 100644 index 0000000..5d40665 --- /dev/null +++ b/bsdiff/LICENSE @@ -0,0 +1,24 @@ + Copyright 2003-2005 Colin Percival + Copyright 2012 Matthew Endsley + All rights reserved + + Redistribution and use in source and binary forms, with or without + modification, are permitted providing that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. diff --git a/bsdiff/Makefile-bsdiff.am b/bsdiff/Makefile-bsdiff.am new file mode 100644 index 0000000..1d810ed --- /dev/null +++ b/bsdiff/Makefile-bsdiff.am @@ -0,0 +1,32 @@ +# Copyright (C) 2015 Giuseppe Scrivano +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted providing that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +EXTRA_DIST += $(libbsdiff_srcpath)/bsdiff.h $(libbsdiff_srcpath)/bspatch.h $(libbsdiff_srcpath)/LICENSE $(libbsdiff_srcpath)/README.md + +libbsdiff_la_SOURCES = \ + $(libbsdiff_srcpath)/bsdiff.c \ + $(libbsdiff_srcpath)/bspatch.c \ + $(NULL) + +libbsdiff_la_CFLAGS = $(AM_CFLAGS) diff --git a/bsdiff/Makefile-bsdiff.am.inc b/bsdiff/Makefile-bsdiff.am.inc new file mode 100644 index 0000000..3db5b63 --- /dev/null +++ b/bsdiff/Makefile-bsdiff.am.inc @@ -0,0 +1,32 @@ +# Copyright (C) 2015 Giuseppe Scrivano +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted providing that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +EXTRA_DIST += bsdiff/bsdiff.h bsdiff/bspatch.h bsdiff/LICENSE bsdiff/README.md + +libbsdiff_la_SOURCES = \ + bsdiff/bsdiff.c \ + bsdiff/bspatch.c \ + $(NULL) + +libbsdiff_la_CFLAGS = $(AM_CFLAGS) diff --git a/bsdiff/README.md b/bsdiff/README.md new file mode 100644 index 0000000..a4b1d23 --- /dev/null +++ b/bsdiff/README.md @@ -0,0 +1,129 @@ +bsdiff/bspatch +============== +bsdiff and bspatch are libraries for building and applying patches to binary +files. + +The original algorithm and implementation was developed by Colin Percival. The +algorithm is detailed in his (unpublished) paper, [Naïve Differences of Executable Code](http://www.daemonology.net/papers/bsdiff.pdf). For more information, visit his +website at . + +I maintain this project seperately from Colin's work, with the goal of making +the core functionality easily embedable in existing projects. + +Contact +------- +[@MatthewEndsley](https://twitter.com/#!/MatthewEndsley) + + +License +------- +Copyright 2003-2005 Colin Percival +Copyright 2012 Matthew Endsley + +This project is governed by the BSD 2-clause license. For details see the file +titled LICENSE in the project root folder. + +Overview +-------- +There are two separate libraries in the project, bsdiff and bspatch. Each are +self contained in bsdiff.c and bspatch.c The easiest way to integrate is to +simply copy the c file to your source folder and build it. + +The overarching goal was to modify the original bsdiff/bspatch code from Colin +and eliminate external dependencies and provide a simple interface to the core +functionality. + +I've exposed relevant functions via the `_stream` classes. The only external +dependency not exposed is `memcmp` in `bsdiff`. + +This library generates patches that are not compatible with the original bsdiff +tool. The impompatibilities were motivated by the patching needs for the game +AirMech and the following requirements: + +* Eliminate/minimize any seek operations when applying patches +* Eliminate any required disk I/O and support embedded streams +* Ability to easily embed the routines as a library instead of an external binary +* Compile+run on all platforms we use to build the game (Windows, Linux, NaCl, OSX) + +Compiling +--------- +The libraries should compile warning free in any moderately recent version of +gcc. The project uses `` which is technically a C99 file and not +available in Microsoft Visual Studio. The easiest solution here is to use the +msinttypes version of stdint.h from . +The direct link for the lazy people is: +. + +If your compiler does not provide an implementation of `` you can +remove the header from the bsdiff/bspatch files and provide your own typedefs +for the following symbols: `uint8_t`, `uint64_t` and `int64_t`. + +Examples +-------- +Each project has an optional main function that serves as an example for using +the library. Simply defined `BSDIFF_EXECUTABLE` or `BSPATCH_EXECUTABLE` to +enable building the standalone tools. + +Reference +--------- +### bsdiff + + struct bsdiff_stream + { + void* opaque; + void* (*malloc)(size_t size); + void (*free)(void* ptr); + int (*write)(struct bsdiff_stream* stream, + const void* buffer, int size); + }; + + int bsdiff(const uint8_t* old, int64_t oldsize, const uint8_t* new, + int64_t newsize, struct bsdiff_stream* stream); + + +In order to use `bsdiff`, you need to define functions for allocating memory and +writing binary data. This behavior is controlled by the `stream` parameted +passed to to `bsdiff(...)`. + +The `opaque` field is never read or modified from within the `bsdiff` function. +The caller can use this field to store custom state data needed for the callback +functions. + +The `malloc` and `free` members should point to functions that behave like the +standard `malloc` and `free` C functions. + +The `write` function is called by bsdiff to write a block of binary data to the +stream. The return value for `write` should be `0` on success and non-zero if +the callback failed to write all data. In the default example, bzip2 is used to +compress output data. + +`bsdiff` returns `0` on success and `-1` on failure. + +### bspatch + + struct bspatch_stream + { + void* opaque; + int (*read)(const struct bspatch_stream* stream, + void* buffer, int length); + }; + + int bspatch(const uint8_t* old, int64_t oldsize, uint8_t* new, + int64_t newsize, struct bspatch_stream* stream); + +The `bspatch` function transforms the data for a file using data generated from +`bsdiff`. The caller takes care of loading the old file and allocating space for +new file data. The `stream` parameter controls the process for reading binary +patch data. + +The `opaque` field is never read or modified from within the bspatch function. +The caller can use this field to store custom state data needed for the read +function. + +The `read` function is called by `bspatch` to read a block of binary data from +the stream. The return value for `read` should be `0` on success and non-zero +if the callback failed to read the requested amount of data. In the default +example, bzip2 is used to decompress input data. + +`bspatch` returns `0` on success and `-1` on failure. On success, `new` contains +the data for the patched file. diff --git a/bsdiff/bsdiff.c b/bsdiff/bsdiff.c new file mode 100644 index 0000000..628f1c1 --- /dev/null +++ b/bsdiff/bsdiff.c @@ -0,0 +1,445 @@ +/*- + * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bsdiff.h" + +#include +#include + +#define MIN(x,y) (((x)<(y)) ? (x) : (y)) + +static void split(int64_t *I,int64_t *V,int64_t start,int64_t len,int64_t h) +{ + int64_t i,j,k,x,tmp,jj,kk; + + if(len<16) { + for(k=start;kstart) split(I,V,start,jj-start,h); + + for(i=0;ikk) split(I,V,kk,start+len-kk,h); +} + +static void qsufsort(int64_t *I,int64_t *V,const uint8_t *old,int64_t oldsize) +{ + int64_t buckets[256]; + int64_t i,h,len; + + for(i=0;i<256;i++) buckets[i]=0; + for(i=0;i0;i--) buckets[i]=buckets[i-1]; + buckets[0]=0; + + for(i=0;iy) { + *pos=I[st]; + return x; + } else { + *pos=I[en]; + return y; + } + }; + + x=st+(en-st)/2; + if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) { + return search(I,old,oldsize,new,newsize,x,en,pos); + } else { + return search(I,old,oldsize,new,newsize,st,x,pos); + }; +} + +static void offtout(int64_t x,uint8_t *buf) +{ + int64_t y; + + if(x<0) y=-x; else y=x; + + buf[0]=y%256;y-=buf[0]; + y=y/256;buf[1]=y%256;y-=buf[1]; + y=y/256;buf[2]=y%256;y-=buf[2]; + y=y/256;buf[3]=y%256;y-=buf[3]; + y=y/256;buf[4]=y%256;y-=buf[4]; + y=y/256;buf[5]=y%256;y-=buf[5]; + y=y/256;buf[6]=y%256;y-=buf[6]; + y=y/256;buf[7]=y%256; + + if(x<0) buf[7]|=0x80; +} + +static int64_t writedata(struct bsdiff_stream* stream, const void* buffer, int64_t length) +{ + int64_t result = 0; + + while (length > 0) + { + const int smallsize = (int)MIN(length, INT_MAX); + const int writeresult = stream->write(stream, buffer, smallsize); + if (writeresult == -1) + { + return -1; + } + + result += writeresult; + length -= smallsize; + buffer = (uint8_t*)buffer + smallsize; + } + + return result; +} + +struct bsdiff_request +{ + const uint8_t* old; + int64_t oldsize; + const uint8_t* new; + int64_t newsize; + struct bsdiff_stream* stream; + int64_t *I; + uint8_t *buffer; +}; + +static int bsdiff_internal(const struct bsdiff_request req) +{ + int64_t *I,*V; + int64_t scan,pos,len; + int64_t lastscan,lastpos,lastoffset; + int64_t oldscore,scsc; + int64_t s,Sf,lenf,Sb,lenb; + int64_t overlap,Ss,lens; + int64_t i; + uint8_t *buffer; + uint8_t buf[8 * 3]; + + if((V=req.stream->malloc((req.oldsize+1)*sizeof(int64_t)))==NULL) return -1; + I = req.I; + + qsufsort(I,V,req.old,req.oldsize); + req.stream->free(V); + + buffer = req.buffer; + + /* Compute the differences, writing ctrl as we go */ + scan=0;len=0;pos=0; + lastscan=0;lastpos=0;lastoffset=0; + while(scanoldscore+8)) break; + + if((scan+lastoffsetSf*2-lenf) { Sf=s; lenf=i; }; + }; + + lenb=0; + if(scan=lastscan+i)&&(pos>=i);i++) { + if(req.old[pos-i]==req.new[scan-i]) s++; + if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; }; + }; + }; + + if(lastscan+lenf>scan-lenb) { + overlap=(lastscan+lenf)-(scan-lenb); + s=0;Ss=0;lens=0; + for(i=0;iSs) { Ss=s; lens=i+1; }; + }; + + lenf+=lens-overlap; + lenb-=lens; + }; + + offtout(lenf,buf); + offtout((scan-lenb)-(lastscan+lenf),buf+8); + offtout((pos-lenb)-(lastpos+lenf),buf+16); + + /* Write control data */ + if (writedata(req.stream, buf, sizeof(buf))) + return -1; + + /* Write diff data */ + for(i=0;imalloc((oldsize+1)*sizeof(int64_t)))==NULL) + return -1; + + if((req.buffer=stream->malloc(newsize+1))==NULL) + { + stream->free(req.I); + return -1; + } + + req.old = old; + req.oldsize = oldsize; + req.new = new; + req.newsize = newsize; + req.stream = stream; + + result = bsdiff_internal(req); + + stream->free(req.buffer); + stream->free(req.I); + + return result; +} + +#if defined(BSDIFF_EXECUTABLE) + +#include + +#include +#include +#include +#include +#include +#include + +static int bz2_write(struct bsdiff_stream* stream, const void* buffer, int size) +{ + int bz2err; + BZFILE* bz2; + + bz2 = (BZFILE*)stream->opaque; + BZ2_bzWrite(&bz2err, bz2, (void*)buffer, size); + if (bz2err != BZ_STREAM_END && bz2err != BZ_OK) + return -1; + + return 0; +} + +int main(int argc,char *argv[]) +{ + int fd; + int bz2err; + uint8_t *old,*new; + off_t oldsize,newsize; + uint8_t buf[8]; + FILE * pf; + struct bsdiff_stream stream; + BZFILE* bz2; + + memset(&bz2, 0, sizeof(bz2)); + stream.malloc = malloc; + stream.free = free; + stream.write = bz2_write; + + if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); + + /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure + that we never try to malloc(0) and get a NULL pointer */ + if(((fd=open(argv[1],O_RDONLY,0))<0) || + ((oldsize=lseek(fd,0,SEEK_END))==-1) || + ((old=malloc(oldsize+1))==NULL) || + (lseek(fd,0,SEEK_SET)!=0) || + (read(fd,old,oldsize)!=oldsize) || + (close(fd)==-1)) err(1,"%s",argv[1]); + + + /* Allocate newsize+1 bytes instead of newsize bytes to ensure + that we never try to malloc(0) and get a NULL pointer */ + if(((fd=open(argv[2],O_RDONLY,0))<0) || + ((newsize=lseek(fd,0,SEEK_END))==-1) || + ((new=malloc(newsize+1))==NULL) || + (lseek(fd,0,SEEK_SET)!=0) || + (read(fd,new,newsize)!=newsize) || + (close(fd)==-1)) err(1,"%s",argv[2]); + + /* Create the patch file */ + if ((pf = fopen(argv[3], "w")) == NULL) + err(1, "%s", argv[3]); + + /* Write header (signature+newsize)*/ + offtout(newsize, buf); + if (fwrite("ENDSLEY/BSDIFF43", 16, 1, pf) != 1 || + fwrite(buf, sizeof(buf), 1, pf) != 1) + err(1, "Failed to write header"); + + + if (NULL == (bz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0))) + errx(1, "BZ2_bzWriteOpen, bz2err=%d", bz2err); + + stream.opaque = bz2; + if (bsdiff(old, oldsize, new, newsize, &stream)) + err(1, "bsdiff"); + + BZ2_bzWriteClose(&bz2err, bz2, 0, NULL, NULL); + if (bz2err != BZ_OK) + err(1, "BZ2_bzWriteClose, bz2err=%d", bz2err); + + if (fclose(pf)) + err(1, "fclose"); + + /* Free the memory we used */ + free(old); + free(new); + + return 0; +} + +#endif diff --git a/bsdiff/bsdiff.h b/bsdiff/bsdiff.h new file mode 100644 index 0000000..b37da5f --- /dev/null +++ b/bsdiff/bsdiff.h @@ -0,0 +1,45 @@ +/*- + * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BSDIFF_H +# define BSDIFF_H + +# include +# include + +struct bsdiff_stream +{ + void* opaque; + + void* (*malloc)(size_t size); + void (*free)(void* ptr); + int (*write)(struct bsdiff_stream* stream, const void* buffer, int size); +}; + +int bsdiff(const uint8_t* old, int64_t oldsize, const uint8_t* new, int64_t newsize, struct bsdiff_stream* stream); + +#endif diff --git a/bsdiff/bspatch.c b/bsdiff/bspatch.c new file mode 100644 index 0000000..881d7e3 --- /dev/null +++ b/bsdiff/bspatch.c @@ -0,0 +1,187 @@ +/*- + * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "bspatch.h" + +static int64_t offtin(uint8_t *buf) +{ + int64_t y; + + y=buf[7]&0x7F; + y=y*256;y+=buf[6]; + y=y*256;y+=buf[5]; + y=y*256;y+=buf[4]; + y=y*256;y+=buf[3]; + y=y*256;y+=buf[2]; + y=y*256;y+=buf[1]; + y=y*256;y+=buf[0]; + + if(buf[7]&0x80) y=-y; + + return y; +} + +int bspatch(const uint8_t* old, int64_t oldsize, uint8_t* new, int64_t newsize, struct bspatch_stream* stream) +{ + uint8_t buf[8]; + int64_t oldpos,newpos; + int64_t ctrl[3]; + int64_t i; + + oldpos=0;newpos=0; + while(newposread(stream, buf, 8)) + return -1; + ctrl[i]=offtin(buf); + }; + + /* Sanity-check */ + if(newpos+ctrl[0]>newsize) + return -1; + + /* Read diff string */ + if (stream->read(stream, new + newpos, ctrl[0])) + return -1; + + /* Add old data to diff string */ + for(i=0;i=0) && (oldpos+inewsize) + return -1; + + /* Read extra string */ + if (stream->read(stream, new + newpos, ctrl[1])) + return -1; + + /* Adjust pointers */ + newpos+=ctrl[1]; + oldpos+=ctrl[2]; + }; + + return 0; +} + +#if defined(BSPATCH_EXECUTABLE) + +#include +#include +#include +#include +#include +#include +#include +#include + +static int bz2_read(const struct bspatch_stream* stream, void* buffer, int length) +{ + int n; + int bz2err; + BZFILE* bz2; + + bz2 = (BZFILE*)stream->opaque; + n = BZ2_bzRead(&bz2err, bz2, buffer, length); + if (n != length) + return -1; + + return 0; +} + +int main(int argc,char * argv[]) +{ + FILE * f; + int fd; + int bz2err; + uint8_t header[24]; + uint8_t *old, *new; + int64_t oldsize, newsize; + BZFILE* bz2; + struct bspatch_stream stream; + + if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); + + /* Open patch file */ + if ((f = fopen(argv[3], "r")) == NULL) + err(1, "fopen(%s)", argv[3]); + + /* Read header */ + if (fread(header, 1, 24, f) != 24) { + if (feof(f)) + errx(1, "Corrupt patch\n"); + err(1, "fread(%s)", argv[3]); + } + + /* Check for appropriate magic */ + if (memcmp(header, "ENDSLEY/BSDIFF43", 16) != 0) + errx(1, "Corrupt patch\n"); + + /* Read lengths from header */ + newsize=offtin(header+16); + if(newsize<0) + errx(1,"Corrupt patch\n"); + + /* Close patch file and re-open it via libbzip2 at the right places */ + if(((fd=open(argv[1],O_RDONLY,0))<0) || + ((oldsize=lseek(fd,0,SEEK_END))==-1) || + ((old=malloc(oldsize+1))==NULL) || + (lseek(fd,0,SEEK_SET)!=0) || + (read(fd,old,oldsize)!=oldsize) || + (close(fd)==-1)) err(1,"%s",argv[1]); + if((new=malloc(newsize+1))==NULL) err(1,NULL); + + if (NULL == (bz2 = BZ2_bzReadOpen(&bz2err, f, 0, 0, NULL, 0))) + errx(1, "BZ2_bzReadOpen, bz2err=%d", bz2err); + + stream.read = bz2_read; + stream.opaque = bz2; + if (bspatch(old, oldsize, new, newsize, &stream)) + errx(1, "bspatch"); + + /* Clean up the bzip2 reads */ + BZ2_bzReadClose(&bz2err, bz2); + fclose(f); + + /* Write the new file */ + if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) || + (write(fd,new,newsize)!=newsize) || (close(fd)==-1)) + err(1,"%s",argv[2]); + + free(new); + free(old); + + return 0; +} + +#endif diff --git a/bsdiff/bspatch.h b/bsdiff/bspatch.h new file mode 100644 index 0000000..099c36e --- /dev/null +++ b/bsdiff/bspatch.h @@ -0,0 +1,42 @@ +/*- + * Copyright 2003-2005 Colin Percival + * Copyright 2012 Matthew Endsley + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BSPATCH_H +# define BSPATCH_H + +# include + +struct bspatch_stream +{ + void* opaque; + int (*read)(const struct bspatch_stream* stream, void* buffer, int length); +}; + +int bspatch(const uint8_t* old, int64_t oldsize, uint8_t* new, int64_t newsize, struct bspatch_stream* stream); + +#endif + diff --git a/build-aux/compile b/build-aux/compile new file mode 100755 index 0000000..99e5052 --- /dev/null +++ b/build-aux/compile @@ -0,0 +1,348 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2018 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# 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 . + +# 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 or send patches to +# . + +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 . +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 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/build-aux/config.guess b/build-aux/config.guess new file mode 100755 index 0000000..b33c9e8 --- /dev/null +++ b/build-aux/config.guess @@ -0,0 +1,1486 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2018 Free Software Foundation, Inc. + +timestamp='2018-08-29' + +# This file 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# 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 Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2018 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 1 2 13 15 +trap 'exitcode=$?; test -z "$tmp" || rm -fr "$tmp"; exit $exitcode' 0 + +set_cc_for_build() { + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD="$driver" + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if test -f /.attbin/uname ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "$UNAME_SYSTEM" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + set_cc_for_build + cat <<-EOF > "$dummy.c" + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" + + # If ldd exists, use it to detect musl libc. + if command -v ldd >/dev/null && \ + ldd --version 2>&1 | grep -q ^musl + then + LIBC=musl + fi + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + "/sbin/$sysctl" 2>/dev/null || \ + "/usr/sbin/$sysctl" 2>/dev/null || \ + echo unknown)` + case "$UNAME_MACHINE_ARCH" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine="${arch}${endian}"-unknown + ;; + *) machine="$UNAME_MACHINE_ARCH"-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "$UNAME_MACHINE_ARCH" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "$UNAME_MACHINE_ARCH" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "$UNAME_VERSION" in + Debian*) + release='-gnu' + ;; + *) + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "$machine-${os}${release}${abi-}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" + exit ;; + *:MidnightBSD:*:*) + echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" + exit ;; + *:ekkoBSD:*:*) + echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" + exit ;; + *:SolidBSD:*:*) + echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd"$UNAME_RELEASE" + exit ;; + *:MirBSD:*:*) + echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" + exit ;; + *:Sortix:*:*) + echo "$UNAME_MACHINE"-unknown-sortix + exit ;; + *:Redox:*:*) + echo "$UNAME_MACHINE"-unknown-redox + exit ;; + mips:OSF1:*.*) + echo mips-dec-osf1 + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo "$UNAME_MACHINE"-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo "$UNAME_MACHINE"-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix"$UNAME_RELEASE" + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux"$UNAME_RELEASE" + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + UNAME_REL="`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" + case `isainfo -b` in + 32) + echo i386-pc-solaris2"$UNAME_REL" + ;; + 64) + echo x86_64-pc-solaris2"$UNAME_REL" + ;; + esac + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos"$UNAME_RELEASE" + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos"$UNAME_RELEASE" + ;; + sun4) + echo sparc-sun-sunos"$UNAME_RELEASE" + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos"$UNAME_RELEASE" + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint"$UNAME_RELEASE" + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint"$UNAME_RELEASE" + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint"$UNAME_RELEASE" + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint"$UNAME_RELEASE" + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten"$UNAME_RELEASE" + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten"$UNAME_RELEASE" + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix"$UNAME_RELEASE" + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix"$UNAME_RELEASE" + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix"$UNAME_RELEASE" + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos"$UNAME_RELEASE" + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] + then + if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ + [ "$TARGET_BINARY_INTERFACE"x = x ] + then + echo m88k-dg-dgux"$UNAME_RELEASE" + else + echo m88k-dg-dguxbcs"$UNAME_RELEASE" + fi + else + echo i586-dg-dgux"$UNAME_RELEASE" + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + fi + echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" + fi + echo "$IBM_ARCH"-ibm-aix"$IBM_REV" + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + case "$UNAME_MACHINE" in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "$sc_cpu_version" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "$sc_kernel_bits" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "$HP_ARCH" = "" ]; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ "$HP_ARCH" = hppa2.0w ] + then + set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo "$HP_ARCH"-hp-hpux"$HPUX_REV" + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux"$HPUX_REV" + exit ;; + 3050*:HI-UX:*:*) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo "$UNAME_MACHINE"-unknown-osf1mk + else + echo "$UNAME_MACHINE"-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi"$UNAME_RELEASE" + exit ;; + *:BSD/OS:*:*) + echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" + exit ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi + else + echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf + fi + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case "$UNAME_PROCESSOR" in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" + exit ;; + i*:CYGWIN*:*) + echo "$UNAME_MACHINE"-pc-cygwin + exit ;; + *:MINGW64*:*) + echo "$UNAME_MACHINE"-pc-mingw64 + exit ;; + *:MINGW*:*) + echo "$UNAME_MACHINE"-pc-mingw32 + exit ;; + *:MSYS*:*) + echo "$UNAME_MACHINE"-pc-msys + exit ;; + i*:PW*:*) + echo "$UNAME_MACHINE"-pc-pw32 + exit ;; + *:Interix*:*) + case "$UNAME_MACHINE" in + x86) + echo i586-pc-interix"$UNAME_RELEASE" + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix"$UNAME_RELEASE" + exit ;; + IA64) + echo ia64-unknown-interix"$UNAME_RELEASE" + exit ;; + esac ;; + i*:UWIN*:*) + echo "$UNAME_MACHINE"-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" + exit ;; + *:GNU:*:*) + # the GNU system + echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" + exit ;; + *:Minix:*:*) + echo "$UNAME_MACHINE"-unknown-minix + exit ;; + aarch64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + arm*:Linux:*:*) + set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi + else + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + cris:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + crisv32:Linux:*:*) + echo "$UNAME_MACHINE"-axis-linux-"$LIBC" + exit ;; + e2k:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + frv:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + hexagon:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + i*86:Linux:*:*) + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" + exit ;; + ia64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + k1om:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m32r*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + m68*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`" + test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; } + ;; + mips64el:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-"$LIBC" + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-"$LIBC" + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-"$LIBC" + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; + PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; + *) echo hppa-unknown-linux-"$LIBC" ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-"$LIBC" + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-"$LIBC" + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-"$LIBC" + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-"$LIBC" + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" + exit ;; + sh64*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sh*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + tile*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + vax:Linux:*:*) + echo "$UNAME_MACHINE"-dec-linux-"$LIBC" + exit ;; + x86_64:Linux:*:*) + echo "$UNAME_MACHINE"-pc-linux-"$LIBC" + exit ;; + xtensa*:Linux:*:*) + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo "$UNAME_MACHINE"-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo "$UNAME_MACHINE"-unknown-stop + exit ;; + i*86:atheos:*:*) + echo "$UNAME_MACHINE"-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo "$UNAME_MACHINE"-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos"$UNAME_RELEASE" + exit ;; + i*86:*DOS:*:*) + echo "$UNAME_MACHINE"-pc-msdosdjgpp + exit ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" + else + echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" + else + echo "$UNAME_MACHINE"-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos"$UNAME_RELEASE" + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos"$UNAME_RELEASE" + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos"$UNAME_RELEASE" + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos"$UNAME_RELEASE" + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv"$UNAME_RELEASE" + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo "$UNAME_MACHINE"-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo "$UNAME_MACHINE"-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux"$UNAME_RELEASE" + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv"$UNAME_RELEASE" + else + echo mips-unknown-sysv"$UNAME_RELEASE" + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux"$UNAME_RELEASE" + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux"$UNAME_RELEASE" + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux"$UNAME_RELEASE" + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux"$UNAME_RELEASE" + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux"$UNAME_RELEASE" + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux"$UNAME_RELEASE" + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux"$UNAME_RELEASE" + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody"$UNAME_RELEASE" + exit ;; + *:Rhapsody:*:*) + echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-*:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSR-*:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSV-*:NONSTOP_KERNEL:*:*) + echo nsv-tandem-nsk"$UNAME_RELEASE" + exit ;; + NSX-*:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk"$UNAME_RELEASE" + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + # shellcheck disable=SC2154 + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo "$UNAME_MACHINE"-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux"$UNAME_RELEASE" + exit ;; + *:DragonFly:*:*) + echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "$UNAME_MACHINE" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" + exit ;; + i*86:rdos:*:*) + echo "$UNAME_MACHINE"-pc-rdos + exit ;; + i*86:AROS:*:*) + echo "$UNAME_MACHINE"-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo "$UNAME_MACHINE"-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +echo "$0: unable to guess system type" >&2 + +case "$UNAME_MACHINE:$UNAME_SYSTEM" in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build-aux/config.sub b/build-aux/config.sub new file mode 100755 index 0000000..b51fb8c --- /dev/null +++ b/build-aux/config.sub @@ -0,0 +1,1790 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2018 Free Software Foundation, Inc. + +timestamp='2018-08-29' + +# This file 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# 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 Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Options: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2018 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo "$1" + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Split fields of configuration type +IFS="-" read -r field1 field2 field3 field4 <&2 + exit 1 + ;; + *-*-*-*) + basic_machine=$field1-$field2 + os=$field3-$field4 + ;; + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \ + | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + os=linux-android + ;; + *) + basic_machine=$field1-$field2 + os=$field3 + ;; + esac + ;; + *-*) + # A lone config we happen to match not fitting any patern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + os= + ;; + *) + basic_machine=$field1 + os=$field2 + ;; + esac + ;; + esac + ;; + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + os=bsd + ;; + a29khif) + basic_machine=a29k-amd + os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=scout + ;; + alliant) + basic_machine=fx80-alliant + os= + ;; + altos | altos3068) + basic_machine=m68k-altos + os= + ;; + am29k) + basic_machine=a29k-none + os=bsd + ;; + amdahl) + basic_machine=580-amdahl + os=sysv + ;; + amiga) + basic_machine=m68k-unknown + os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=bsd + ;; + aros) + basic_machine=i386-pc + os=aros + ;; + aux) + basic_machine=m68k-apple + os=aux + ;; + balance) + basic_machine=ns32k-sequent + os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=linux + ;; + cegcc) + basic_machine=arm-unknown + os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=bsd + ;; + convex-c2) + basic_machine=c2-convex + os=bsd + ;; + convex-c32) + basic_machine=c32-convex + os=bsd + ;; + convex-c34) + basic_machine=c34-convex + os=bsd + ;; + convex-c38) + basic_machine=c38-convex + os=bsd + ;; + cray) + basic_machine=j90-cray + os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + os= + ;; + da30) + basic_machine=m68k-da30 + os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + os= + ;; + delta88) + basic_machine=m88k-motorola + os=sysv3 + ;; + dicos) + basic_machine=i686-pc + os=dicos + ;; + djgpp) + basic_machine=i586-pc + os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=ose + ;; + gmicro) + basic_machine=tron-gmicro + os=sysv + ;; + go32) + basic_machine=i386-pc + os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=hms + ;; + harris) + basic_machine=m88k-harris + os=sysv3 + ;; + hp300) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=hpux + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=proelf + ;; + i386mach) + basic_machine=i386-mach + os=mach + ;; + vsta) + basic_machine=i386-pc + os=vsta + ;; + isi68 | isi) + basic_machine=m68k-isi + os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + os=sysv + ;; + merlin) + basic_machine=ns32k-utek + os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + os=coff + ;; + morphos) + basic_machine=powerpc-unknown + os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=moxiebox + ;; + msdos) + basic_machine=i386-pc + os=msdos + ;; + msys) + basic_machine=i686-pc + os=msys + ;; + mvs) + basic_machine=i370-ibm + os=mvs + ;; + nacl) + basic_machine=le32-unknown + os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=newsos + ;; + news1000) + basic_machine=m68030-sony + os=newsos + ;; + necv70) + basic_machine=v70-nec + os=sysv + ;; + nh3000) + basic_machine=m68k-harris + os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=cxux + ;; + nindy960) + basic_machine=i960-intel + os=nindy + ;; + mon960) + basic_machine=i960-intel + os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=ose + ;; + os68k) + basic_machine=m68k-none + os=os68k + ;; + paragon) + basic_machine=i860-intel + os=osf + ;; + parisc) + basic_machine=hppa-unknown + os=linux + ;; + pw32) + basic_machine=i586-unknown + os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=rdos + ;; + rdos32) + basic_machine=i386-pc + os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=coff + ;; + sa29200) + basic_machine=a29k-amd + os=udi + ;; + sei) + basic_machine=mips-sei + os=seiux + ;; + sequent) + basic_machine=i386-sequent + os= + ;; + sps7) + basic_machine=m68k-bull + os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + os= + ;; + stratus) + basic_machine=i860-stratus + os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + os= + ;; + sun2os3) + basic_machine=m68000-sun + os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + os= + ;; + sun3os3) + basic_machine=m68k-sun + os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + os= + ;; + sun4os3) + basic_machine=sparc-sun + os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + os= + ;; + sv1) + basic_machine=sv1-cray + os=unicos + ;; + symmetry) + basic_machine=i386-sequent + os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=unicos + ;; + t90) + basic_machine=t90-cray + os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + os=tpf + ;; + udi29k) + basic_machine=a29k-amd + os=udi + ;; + ultra3) + basic_machine=a29k-nyu + os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=none + ;; + vaxv) + basic_machine=vax-dec + os=sysv + ;; + vms) + basic_machine=vax-dec + os=vms + ;; + vxworks960) + basic_machine=i960-wrs + os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=vxworks + ;; + xbox) + basic_machine=i686-pc + os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + os=unicos + ;; + *) + basic_machine=$1 + os= + ;; + esac + ;; +esac + +# Decode 1-component or ad-hoc basic machines +case $basic_machine in + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond + ;; + op50n) + cpu=hppa1.1 + vendor=oki + ;; + op60c) + cpu=hppa1.1 + vendor=oki + ;; + ibm*) + cpu=i370 + vendor=ibm + ;; + orion105) + cpu=clipper + vendor=highlevel + ;; + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple + ;; + pmac | pmac-mpw) + cpu=powerpc + vendor=apple + ;; + + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att + ;; + 3b*) + cpu=we32k + vendor=att + ;; + bluegene*) + cpu=powerpc + vendor=ibm + os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + os=${os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + os=sysv32 + ;; + i*86v4*) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + os=sysv4 + ;; + i*86v) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + os=sysv + ;; + i*86sol2) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + os=${os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $os in + irix*) + ;; + *) + os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $os in + nextstep* ) + ;; + ns2*) + os=nextstep2 + ;; + *) + os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + os=${os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + os=proelf + ;; + none) + cpu=none + vendor=none + ;; + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=`echo "$basic_machine" | sed 's/-.*//'` + ;; + + *-*) + IFS="-" read -r cpu vendor <&2 + exit 1 + ;; + esac + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $vendor in + digital*) + vendor=dec + ;; + commodore*) + vendor=cbm + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x$os != x ] +then +case $os in + # First match some system type aliases that might get confused + # with valid system types. + # solaris* is a basic system type, with this one exception. + auroraux) + os=auroraux + ;; + bluegene*) + os=cnk + ;; + solaris1 | solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + solaris) + os=solaris2 + ;; + unixware*) + os=sysv4.2uw + ;; + gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # es1800 is here to avoid being matched by es* (a different OS) + es1800*) + os=ose + ;; + # Some version numbers need modification + chorusos*) + os=chorusos + ;; + isc) + os=isc2.2 + ;; + sco6) + os=sco5v6 + ;; + sco5) + os=sco3.2v5 + ;; + sco4) + os=sco3.2v4 + ;; + sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + ;; + sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + scout) + # Don't match below + ;; + sco*) + os=sco3.2v2 + ;; + psos*) + os=psos + ;; + # Now accept the basic system types. + # The portable systems comes first. + # Each alternative MUST end in a * to match a version number. + # sysv* is not here because it comes later, after sysvr4. + gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | kopensolaris* | plan9* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ + | knetbsd* | mirbsd* | netbsd* \ + | bitrig* | openbsd* | solidbsd* | libertybsd* \ + | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \ + | linux-newlib* | linux-musl* | linux-uclibc* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* \ + | os2* | vos* | palmos* | uclinux* | nucleus* \ + | morphos* | superux* | rtmk* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + qnx*) + case $cpu in + x86 | i*86) + ;; + *) + os=nto-$os + ;; + esac + ;; + hiux*) + os=hiuxwe2 + ;; + nto-qnx*) + ;; + nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + sim | xray | os68k* | v88r* \ + | windows* | osx | abug | netware* | os9* \ + | macos* | mpw* | magic* | mmixware* | mon960* | lnews*) + ;; + linux-dietlibc) + os=linux-dietlibc + ;; + linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + lynx*178) + os=lynxos178 + ;; + lynx*5) + os=lynxos5 + ;; + lynx*) + os=lynxos + ;; + mac*) + os=`echo "$os" | sed -e 's|mac|macos|'` + ;; + opened*) + os=openedition + ;; + os400*) + os=os400 + ;; + sunos5*) + os=`echo "$os" | sed -e 's|sunos5|solaris2|'` + ;; + sunos6*) + os=`echo "$os" | sed -e 's|sunos6|solaris3|'` + ;; + wince*) + os=wince + ;; + utek*) + os=bsd + ;; + dynix*) + os=bsd + ;; + acis*) + os=aos + ;; + atheos*) + os=atheos + ;; + syllable*) + os=syllable + ;; + 386bsd) + os=bsd + ;; + ctix* | uts*) + os=sysv + ;; + nova*) + os=rtmk-nova + ;; + ns2) + os=nextstep2 + ;; + nsk*) + os=nsk + ;; + # Preserve the version number of sinix5. + sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + sinix*) + os=sysv4 + ;; + tpf*) + os=tpf + ;; + triton*) + os=sysv3 + ;; + oss*) + os=sysv3 + ;; + svr4*) + os=sysv4 + ;; + svr3) + os=sysv3 + ;; + sysvr4) + os=sysv4 + ;; + # This must come after sysvr4. + sysv*) + ;; + ose*) + os=ose + ;; + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) + os=mint + ;; + zvmoe) + os=zvmoe + ;; + dicos*) + os=dicos + ;; + pikeos*) + # Until real need of OS specific support for + # particular features comes up, bare metal + # configurations are quite functional. + case $cpu in + arm*) + os=eabi + ;; + *) + os=elf + ;; + esac + ;; + nacl*) + ;; + ios) + ;; + none) + ;; + *-eabi) + ;; + *) + echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $cpu-$vendor in + score-*) + os=elf + ;; + spu-*) + os=elf + ;; + *-acorn) + os=riscix1.2 + ;; + arm*-rebel) + os=linux + ;; + arm*-semi) + os=aout + ;; + c4x-* | tic4x-*) + os=coff + ;; + c8051-*) + os=elf + ;; + clipper-intergraph) + os=clix + ;; + hexagon-*) + os=elf + ;; + tic54x-*) + os=coff + ;; + tic55x-*) + os=coff + ;; + tic6x-*) + os=coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=tops20 + ;; + pdp11-*) + os=none + ;; + *-dec | vax-*) + os=ultrix4.2 + ;; + m68*-apollo) + os=domain + ;; + i386-sun) + os=sunos4.0.2 + ;; + m68000-sun) + os=sunos3 + ;; + m68*-cisco) + os=aout + ;; + mep-*) + os=elf + ;; + mips*-cisco) + os=elf + ;; + mips*-*) + os=elf + ;; + or32-*) + os=coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=sysv3 + ;; + sparc-* | *-sun) + os=sunos4.1.1 + ;; + pru-*) + os=elf + ;; + *-be) + os=beos + ;; + *-ibm) + os=aix + ;; + *-knuth) + os=mmixware + ;; + *-wec) + os=proelf + ;; + *-winbond) + os=proelf + ;; + *-oki) + os=proelf + ;; + *-hp) + os=hpux + ;; + *-hitachi) + os=hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=sysv + ;; + *-cbm) + os=amigaos + ;; + *-dg) + os=dgux + ;; + *-dolphin) + os=sysv3 + ;; + m68k-ccur) + os=rtu + ;; + m88k-omron*) + os=luna + ;; + *-next) + os=nextstep + ;; + *-sequent) + os=ptx + ;; + *-crds) + os=unos + ;; + *-ns) + os=genix + ;; + i370-*) + os=mvs + ;; + *-gould) + os=sysv + ;; + *-highlevel) + os=bsd + ;; + *-encore) + os=bsd + ;; + *-sgi) + os=irix + ;; + *-siemens) + os=sysv4 + ;; + *-masscomp) + os=rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=uxpv + ;; + *-rom68k) + os=coff + ;; + *-*bug) + os=coff + ;; + *-apple) + os=macos + ;; + *-atari*) + os=mint + ;; + *-wrs) + os=vxworks + ;; + *) + os=none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +case $vendor in + unknown) + case $os in + riscix*) + vendor=acorn + ;; + sunos*) + vendor=sun + ;; + cnk*|-aix*) + vendor=ibm + ;; + beos*) + vendor=be + ;; + hpux*) + vendor=hp + ;; + mpeix*) + vendor=hp + ;; + hiux*) + vendor=hitachi + ;; + unos*) + vendor=crds + ;; + dgux*) + vendor=dg + ;; + luna*) + vendor=omron + ;; + genix*) + vendor=ns + ;; + clix*) + vendor=intergraph + ;; + mvs* | opened*) + vendor=ibm + ;; + os400*) + vendor=ibm + ;; + ptx*) + vendor=sequent + ;; + tpf*) + vendor=ibm + ;; + vxsim* | vxworks* | windiss*) + vendor=wrs + ;; + aux*) + vendor=apple + ;; + hms*) + vendor=hitachi + ;; + mpw* | macos*) + vendor=apple + ;; + *mint | mint[0-9]* | *MiNT | MiNT[0-9]*) + vendor=atari + ;; + vos*) + vendor=stratus + ;; + esac + ;; +esac + +echo "$cpu-$vendor-$os" +exit + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build-aux/depcomp b/build-aux/depcomp new file mode 100755 index 0000000..65cbf70 --- /dev/null +++ b/build-aux/depcomp @@ -0,0 +1,791 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1999-2018 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 . + +# 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 . + +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 . +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 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/build-aux/install-sh b/build-aux/install-sh new file mode 100755 index 0000000..8175c64 --- /dev/null +++ b/build-aux/install-sh @@ -0,0 +1,518 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2018-03-11.20; # 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. + 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 + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + 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. + ;; + *) + # Note that $RANDOM variable is not portable (e.g. dash); Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p' feature. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/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. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 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=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_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 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/build-aux/ltmain.sh b/build-aux/ltmain.sh new file mode 100644 index 0000000..7f3523d --- /dev/null +++ b/build-aux/ltmain.sh @@ -0,0 +1,11149 @@ +#! /bin/sh +## DO NOT EDIT - This file generated from ./build-aux/ltmain.in +## by inline-source v2014-01-03.01 + +# libtool (GNU libtool) 2.4.6 +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996-2015 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 . + + +PROGRAM=libtool +PACKAGE=libtool +VERSION=2.4.6 +package_revision=2.4.6 + + +## ------ ## +## Usage. ## +## ------ ## + +# Run './libtool --help' for help with using this script from the +# command line. + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# After configure completes, it has a better idea of some of the +# shell tools we need than the defaults used by the functions shared +# with bootstrap, so set those here where they can still be over- +# ridden by the user, but otherwise take precedence. + +: ${AUTOCONF="autoconf"} +: ${AUTOMAKE="automake"} + + +## -------------------------- ## +## Source external libraries. ## +## -------------------------- ## + +# Much of our low-level functionality needs to be sourced from external +# libraries, which are installed to $pkgauxdir. + +# Set a version string for this script. +scriptversion=2015-01-20.17; # UTC + +# General shell script boiler plate, and helper functions. +# Written by Gary V. Vaughan, 2004 + +# Copyright (C) 2004-2015 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# 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 3 of the License, or +# (at your option) any later version. + +# As a special exception to the GNU General Public License, if you distribute +# this file as part of a program or library that is built using GNU Libtool, +# you may include this file under the same distribution terms that you use +# for the rest of that program. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNES 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 . + +# Please report bugs or propose patches to gary@gnu.org. + + +## ------ ## +## Usage. ## +## ------ ## + +# Evaluate this file near the top of your script to gain access to +# the functions and variables defined here: +# +# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh +# +# If you need to override any of the default environment variable +# settings, do that before evaluating this file. + + +## -------------------- ## +## Shell normalisation. ## +## -------------------- ## + +# Some shells need a little help to be as Bourne compatible as possible. +# Before doing anything else, make sure all that help has been provided! + +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac +fi + +# NLS nuisances: We save the old values in case they are required later. +_G_user_locale= +_G_safe_locale= +for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test set = \"\${$_G_var+set}\"; then + save_$_G_var=\$$_G_var + $_G_var=C + export $_G_var + _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" + _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" + fi" +done + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Make sure IFS has a sensible default +sp=' ' +nl=' +' +IFS="$sp $nl" + +# There are apparently some retarded systems that use ';' as a PATH separator! +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + + +## ------------------------- ## +## Locate command utilities. ## +## ------------------------- ## + + +# func_executable_p FILE +# ---------------------- +# Check that FILE is an executable regular file. +func_executable_p () +{ + test -f "$1" && test -x "$1" +} + + +# func_path_progs PROGS_LIST CHECK_FUNC [PATH] +# -------------------------------------------- +# Search for either a program that responds to --version with output +# containing "GNU", or else returned by CHECK_FUNC otherwise, by +# trying all the directories in PATH with each of the elements of +# PROGS_LIST. +# +# CHECK_FUNC should accept the path to a candidate program, and +# set $func_check_prog_result if it truncates its output less than +# $_G_path_prog_max characters. +func_path_progs () +{ + _G_progs_list=$1 + _G_check_func=$2 + _G_PATH=${3-"$PATH"} + + _G_path_prog_max=0 + _G_path_prog_found=false + _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} + for _G_dir in $_G_PATH; do + IFS=$_G_save_IFS + test -z "$_G_dir" && _G_dir=. + for _G_prog_name in $_G_progs_list; do + for _exeext in '' .EXE; do + _G_path_prog=$_G_dir/$_G_prog_name$_exeext + func_executable_p "$_G_path_prog" || continue + case `"$_G_path_prog" --version 2>&1` in + *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; + *) $_G_check_func $_G_path_prog + func_path_progs_result=$func_check_prog_result + ;; + esac + $_G_path_prog_found && break 3 + done + done + done + IFS=$_G_save_IFS + test -z "$func_path_progs_result" && { + echo "no acceptable sed could be found in \$PATH" >&2 + exit 1 + } +} + + +# We want to be able to use the functions in this file before configure +# has figured out where the best binaries are kept, which means we have +# to search for them ourselves - except when the results are already set +# where we skip the searches. + +# Unless the user overrides by setting SED, search the path for either GNU +# sed, or the sed that truncates its output the least. +test -z "$SED" && { + _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for _G_i in 1 2 3 4 5 6 7; do + _G_sed_script=$_G_sed_script$nl$_G_sed_script + done + echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed + _G_sed_script= + + func_check_prog_sed () + { + _G_path_prog=$1 + + _G_count=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo '' >> conftest.nl + "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin + rm -f conftest.sed + SED=$func_path_progs_result +} + + +# Unless the user overrides by setting GREP, search the path for either GNU +# grep, or the grep that truncates its output the least. +test -z "$GREP" && { + func_check_prog_grep () + { + _G_path_prog=$1 + + _G_count=0 + _G_path_prog_max=0 + printf 0123456789 >conftest.in + while : + do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo 'GREP' >> conftest.nl + "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break + diff conftest.out conftest.nl >/dev/null 2>&1 || break + _G_count=`expr $_G_count + 1` + if test "$_G_count" -gt "$_G_path_prog_max"; then + # Best one so far, save it but keep looking for a better one + func_check_prog_result=$_G_path_prog + _G_path_prog_max=$_G_count + fi + # 10*(2^10) chars as input seems more than enough + test 10 -lt "$_G_count" && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out + } + + func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin + GREP=$func_path_progs_result +} + + +## ------------------------------- ## +## User overridable command paths. ## +## ------------------------------- ## + +# All uppercase variable names are used for environment variables. These +# variables can be overridden by the user before calling a script that +# uses them if a suitable command of that name is not already available +# in the command search PATH. + +: ${CP="cp -f"} +: ${ECHO="printf %s\n"} +: ${EGREP="$GREP -E"} +: ${FGREP="$GREP -F"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} + + +## -------------------- ## +## Useful sed snippets. ## +## -------------------- ## + +sed_dirname='s|/[^/]*$||' +sed_basename='s|^.*/||' + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s|\([`"$\\]\)|\\\1|g' + +# Same as above, but do not quote variable references. +sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' + +# Sed substitution that converts a w32 file name or path +# that contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-'\' parameter expansions in output of sed_double_quote_subst that +# were '\'-ed in input to the same. If an odd number of '\' preceded a +# '$' in input to sed_double_quote_subst, that '$' was protected from +# expansion. Since each input '\' is now two '\'s, look for any number +# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. +_G_bs='\\' +_G_bs2='\\\\' +_G_bs4='\\\\\\\\' +_G_dollar='\$' +sed_double_backslash="\ + s/$_G_bs4/&\\ +/g + s/^$_G_bs2$_G_dollar/$_G_bs&/ + s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g + s/\n//g" + + +## ----------------- ## +## Global variables. ## +## ----------------- ## + +# Except for the global variables explicitly listed below, the following +# functions in the '^func_' namespace, and the '^require_' namespace +# variables initialised in the 'Resource management' section, sourcing +# this file will not pollute your global namespace with anything +# else. There's no portable way to scope variables in Bourne shell +# though, so actually running these functions will sometimes place +# results into a variable named after the function, and often use +# temporary variables in the '^_G_' namespace. If you are careful to +# avoid using those namespaces casually in your sourcing script, things +# should continue to work as you expect. And, of course, you can freely +# overwrite any of the functions or variables defined here before +# calling anything to customize them. + +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +# Allow overriding, eg assuming that you follow the convention of +# putting '$debug_cmd' at the start of all your functions, you can get +# bash to show function call trace with: +# +# debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name +debug_cmd=${debug_cmd-":"} +exit_cmd=: + +# By convention, finish your script with: +# +# exit $exit_status +# +# so that you can set exit_status to non-zero if you want to indicate +# something went wrong during execution without actually bailing out at +# the point of failure. +exit_status=$EXIT_SUCCESS + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath=$0 + +# The name of this program. +progname=`$ECHO "$progpath" |$SED "$sed_basename"` + +# Make sure we have an absolute progpath for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` + progdir=`cd "$progdir" && pwd` + progpath=$progdir/$progname + ;; + *) + _G_IFS=$IFS + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS=$_G_IFS + test -x "$progdir/$progname" && break + done + IFS=$_G_IFS + test -n "$progdir" || progdir=`pwd` + progpath=$progdir/$progname + ;; +esac + + +## ----------------- ## +## Standard options. ## +## ----------------- ## + +# The following options affect the operation of the functions defined +# below, and should be set appropriately depending on run-time para- +# meters passed on the command line. + +opt_dry_run=false +opt_quiet=false +opt_verbose=false + +# Categories 'all' and 'none' are always available. Append any others +# you will pass as the first argument to func_warning from your own +# code. +warning_categories= + +# By default, display warnings according to 'opt_warning_types'. Set +# 'warning_func' to ':' to elide all warnings, or func_fatal_error to +# treat the next displayed warning as a fatal error. +warning_func=func_warn_and_continue + +# Set to 'all' to display all warnings, 'none' to suppress all +# warnings, or a space delimited list of some subset of +# 'warning_categories' to display only the listed warnings. +opt_warning_types=all + + +## -------------------- ## +## Resource management. ## +## -------------------- ## + +# This section contains definitions for functions that each ensure a +# particular resource (a file, or a non-empty configuration variable for +# example) is available, and if appropriate to extract default values +# from pertinent package files. Call them using their associated +# 'require_*' variable to ensure that they are executed, at most, once. +# +# It's entirely deliberate that calling these functions can set +# variables that don't obey the namespace limitations obeyed by the rest +# of this file, in order that that they be as useful as possible to +# callers. + + +# require_term_colors +# ------------------- +# Allow display of bold text on terminals that support it. +require_term_colors=func_require_term_colors +func_require_term_colors () +{ + $debug_cmd + + test -t 1 && { + # COLORTERM and USE_ANSI_COLORS environment variables take + # precedence, because most terminfo databases neglect to describe + # whether color sequences are supported. + test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} + + if test 1 = "$USE_ANSI_COLORS"; then + # Standard ANSI escape sequences + tc_reset='' + tc_bold=''; tc_standout='' + tc_red=''; tc_green='' + tc_blue=''; tc_cyan='' + else + # Otherwise trust the terminfo database after all. + test -n "`tput sgr0 2>/dev/null`" && { + tc_reset=`tput sgr0` + test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` + tc_standout=$tc_bold + test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` + test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` + test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` + test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` + test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` + } + fi + } + + require_term_colors=: +} + + +## ----------------- ## +## Function library. ## +## ----------------- ## + +# This section contains a variety of useful functions to call in your +# scripts. Take note of the portable wrappers for features provided by +# some modern shells, which will fall back to slower equivalents on +# less featureful shells. + + +# func_append VAR VALUE +# --------------------- +# Append VALUE onto the existing contents of VAR. + + # We should try to minimise forks, especially on Windows where they are + # unreasonably slow, so skip the feature probes when bash or zsh are + # being used: + if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then + : ${_G_HAVE_ARITH_OP="yes"} + : ${_G_HAVE_XSI_OPS="yes"} + # The += operator was introduced in bash 3.1 + case $BASH_VERSION in + [12].* | 3.0 | 3.0*) ;; + *) + : ${_G_HAVE_PLUSEQ_OP="yes"} + ;; + esac + fi + + # _G_HAVE_PLUSEQ_OP + # Can be empty, in which case the shell is probed, "yes" if += is + # useable or anything else if it does not work. + test -z "$_G_HAVE_PLUSEQ_OP" \ + && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ + && _G_HAVE_PLUSEQ_OP=yes + +if test yes = "$_G_HAVE_PLUSEQ_OP" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_append () + { + $debug_cmd + + eval "$1+=\$2" + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_append () + { + $debug_cmd + + eval "$1=\$$1\$2" + } +fi + + +# func_append_quoted VAR VALUE +# ---------------------------- +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +if test yes = "$_G_HAVE_PLUSEQ_OP"; then + eval 'func_append_quoted () + { + $debug_cmd + + func_quote_for_eval "$2" + eval "$1+=\\ \$func_quote_for_eval_result" + }' +else + func_append_quoted () + { + $debug_cmd + + func_quote_for_eval "$2" + eval "$1=\$$1\\ \$func_quote_for_eval_result" + } +fi + + +# func_append_uniq VAR VALUE +# -------------------------- +# Append unique VALUE onto the existing contents of VAR, assuming +# entries are delimited by the first character of VALUE. For example: +# +# func_append_uniq options " --another-option option-argument" +# +# will only append to $options if " --another-option option-argument " +# is not already present somewhere in $options already (note spaces at +# each end implied by leading space in second argument). +func_append_uniq () +{ + $debug_cmd + + eval _G_current_value='`$ECHO $'$1'`' + _G_delim=`expr "$2" : '\(.\)'` + + case $_G_delim$_G_current_value$_G_delim in + *"$2$_G_delim"*) ;; + *) func_append "$@" ;; + esac +} + + +# func_arith TERM... +# ------------------ +# Set func_arith_result to the result of evaluating TERMs. + test -z "$_G_HAVE_ARITH_OP" \ + && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ + && _G_HAVE_ARITH_OP=yes + +if test yes = "$_G_HAVE_ARITH_OP"; then + eval 'func_arith () + { + $debug_cmd + + func_arith_result=$(( $* )) + }' +else + func_arith () + { + $debug_cmd + + func_arith_result=`expr "$@"` + } +fi + + +# func_basename FILE +# ------------------ +# Set func_basename_result to FILE with everything up to and including +# the last / stripped. +if test yes = "$_G_HAVE_XSI_OPS"; then + # If this shell supports suffix pattern removal, then use it to avoid + # forking. Hide the definitions single quotes in case the shell chokes + # on unsupported syntax... + _b='func_basename_result=${1##*/}' + _d='case $1 in + */*) func_dirname_result=${1%/*}$2 ;; + * ) func_dirname_result=$3 ;; + esac' + +else + # ...otherwise fall back to using sed. + _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' + _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` + if test "X$func_dirname_result" = "X$1"; then + func_dirname_result=$3 + else + func_append func_dirname_result "$2" + fi' +fi + +eval 'func_basename () +{ + $debug_cmd + + '"$_b"' +}' + + +# func_dirname FILE APPEND NONDIR_REPLACEMENT +# ------------------------------------------- +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +eval 'func_dirname () +{ + $debug_cmd + + '"$_d"' +}' + + +# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT +# -------------------------------------------------------- +# Perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# For efficiency, we do not delegate to the functions above but instead +# duplicate the functionality here. +eval 'func_dirname_and_basename () +{ + $debug_cmd + + '"$_b"' + '"$_d"' +}' + + +# func_echo ARG... +# ---------------- +# Echo program name prefixed message. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_echo_all ARG... +# -------------------- +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + + +# func_echo_infix_1 INFIX ARG... +# ------------------------------ +# Echo program name, followed by INFIX on the first line, with any +# additional lines not showing INFIX. +func_echo_infix_1 () +{ + $debug_cmd + + $require_term_colors + + _G_infix=$1; shift + _G_indent=$_G_infix + _G_prefix="$progname: $_G_infix: " + _G_message=$* + + # Strip color escape sequences before counting printable length + for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" + do + test -n "$_G_tc" && { + _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` + _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` + } + done + _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes + + func_echo_infix_1_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_infix_1_IFS + $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 + _G_prefix=$_G_indent + done + IFS=$func_echo_infix_1_IFS +} + + +# func_error ARG... +# ----------------- +# Echo program name prefixed message to standard error. +func_error () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 +} + + +# func_fatal_error ARG... +# ----------------------- +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + $debug_cmd + + func_error "$*" + exit $EXIT_FAILURE +} + + +# func_grep EXPRESSION FILENAME +# ----------------------------- +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $debug_cmd + + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_len STRING +# --------------- +# Set func_len_result to the length of STRING. STRING may not +# start with a hyphen. + test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_len () + { + $debug_cmd + + func_len_result=${#1} + }' +else + func_len () + { + $debug_cmd + + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` + } +fi + + +# func_mkdir_p DIRECTORY-PATH +# --------------------------- +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + $debug_cmd + + _G_directory_path=$1 + _G_dir_list= + + if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then + + # Protect directory names starting with '-' + case $_G_directory_path in + -*) _G_directory_path=./$_G_directory_path ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$_G_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + _G_dir_list=$_G_directory_path:$_G_dir_list + + # If the last portion added has no slash in it, the list is done + case $_G_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` + done + _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` + + func_mkdir_p_IFS=$IFS; IFS=: + for _G_dir in $_G_dir_list; do + IFS=$func_mkdir_p_IFS + # mkdir can fail with a 'File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$_G_dir" 2>/dev/null || : + done + IFS=$func_mkdir_p_IFS + + # Bail out if we (or some other process) failed to create a directory. + test -d "$_G_directory_path" || \ + func_fatal_error "Failed to create '$1'" + fi +} + + +# func_mktempdir [BASENAME] +# ------------------------- +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, BASENAME is the basename for that directory. +func_mktempdir () +{ + $debug_cmd + + _G_template=${TMPDIR-/tmp}/${1-$progname} + + if test : = "$opt_dry_run"; then + # Return a directory name, but don't create it in dry-run mode + _G_tmpdir=$_G_template-$$ + else + + # If mktemp works, use that first and foremost + _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` + + if test ! -d "$_G_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + _G_tmpdir=$_G_template-${RANDOM-0}$$ + + func_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$_G_tmpdir" + umask $func_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$_G_tmpdir" || \ + func_fatal_error "cannot create temporary directory '$_G_tmpdir'" + fi + + $ECHO "$_G_tmpdir" +} + + +# func_normal_abspath PATH +# ------------------------ +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +func_normal_abspath () +{ + $debug_cmd + + # These SED scripts presuppose an absolute path with a trailing slash. + _G_pathcar='s|^/\([^/]*\).*$|\1|' + _G_pathcdr='s|^/[^/]*||' + _G_removedotparts=':dotsl + s|/\./|/|g + t dotsl + s|/\.$|/|' + _G_collapseslashes='s|/\{1,\}|/|g' + _G_finalslash='s|/*$|/|' + + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` + while :; do + # Processed it all yet? + if test / = "$func_normal_abspath_tpath"; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result"; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$_G_pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + + +# func_notquiet ARG... +# -------------------- +# Echo program name prefixed message only when not in quiet mode. +func_notquiet () +{ + $debug_cmd + + $opt_quiet || func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + + +# func_relative_path SRCDIR DSTDIR +# -------------------------------- +# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. +func_relative_path () +{ + $debug_cmd + + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=$func_dirname_result + if test -z "$func_relative_path_tlibdir"; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test -n "$func_stripname_result"; then + func_append func_relative_path_result "/$func_stripname_result" + fi + + # Normalisation. If bindir is libdir, return '.' else relative path. + if test -n "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + fi + + test -n "$func_relative_path_result" || func_relative_path_result=. + + : +} + + +# func_quote_for_eval ARG... +# -------------------------- +# Aesthetically quote ARGs to be evaled later. +# This function returns two values: +# i) func_quote_for_eval_result +# double-quoted, suitable for a subsequent eval +# ii) func_quote_for_eval_unquoted_result +# has all characters that are still active within double +# quotes backslashified. +func_quote_for_eval () +{ + $debug_cmd + + func_quote_for_eval_unquoted_result= + func_quote_for_eval_result= + while test 0 -lt $#; do + case $1 in + *[\\\`\"\$]*) + _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; + *) + _G_unquoted_arg=$1 ;; + esac + if test -n "$func_quote_for_eval_unquoted_result"; then + func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" + else + func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" + fi + + case $_G_unquoted_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and variable expansion + # for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + _G_quoted_arg=\"$_G_unquoted_arg\" + ;; + *) + _G_quoted_arg=$_G_unquoted_arg + ;; + esac + + if test -n "$func_quote_for_eval_result"; then + func_append func_quote_for_eval_result " $_G_quoted_arg" + else + func_append func_quote_for_eval_result "$_G_quoted_arg" + fi + shift + done +} + + +# func_quote_for_expand ARG +# ------------------------- +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + $debug_cmd + + case $1 in + *[\\\`\"]*) + _G_arg=`$ECHO "$1" | $SED \ + -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; + *) + _G_arg=$1 ;; + esac + + case $_G_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + _G_arg=\"$_G_arg\" + ;; + esac + + func_quote_for_expand_result=$_G_arg +} + + +# func_stripname PREFIX SUFFIX NAME +# --------------------------------- +# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_stripname () + { + $debug_cmd + + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary variable first. + func_stripname_result=$3 + func_stripname_result=${func_stripname_result#"$1"} + func_stripname_result=${func_stripname_result%"$2"} + }' +else + func_stripname () + { + $debug_cmd + + case $2 in + .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; + *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; + esac + } +fi + + +# func_show_eval CMD [FAIL_EXP] +# ----------------------------- +# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + func_quote_for_expand "$_G_cmd" + eval "func_notquiet $func_quote_for_expand_result" + + $opt_dry_run || { + eval "$_G_cmd" + _G_status=$? + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_show_eval_locale CMD [FAIL_EXP] +# ------------------------------------ +# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + $debug_cmd + + _G_cmd=$1 + _G_fail_exp=${2-':'} + + $opt_quiet || { + func_quote_for_expand "$_G_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + $opt_dry_run || { + eval "$_G_user_locale + $_G_cmd" + _G_status=$? + eval "$_G_safe_locale" + if test 0 -ne "$_G_status"; then + eval "(exit $_G_status); $_G_fail_exp" + fi + } +} + + +# func_tr_sh +# ---------- +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + $debug_cmd + + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_verbose ARG... +# ------------------- +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $debug_cmd + + $opt_verbose && func_echo "$*" + + : +} + + +# func_warn_and_continue ARG... +# ----------------------------- +# Echo program name prefixed warning message to standard error. +func_warn_and_continue () +{ + $debug_cmd + + $require_term_colors + + func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 +} + + +# func_warning CATEGORY ARG... +# ---------------------------- +# Echo program name prefixed warning message to standard error. Warning +# messages can be filtered according to CATEGORY, where this function +# elides messages where CATEGORY is not listed in the global variable +# 'opt_warning_types'. +func_warning () +{ + $debug_cmd + + # CATEGORY must be in the warning_categories list! + case " $warning_categories " in + *" $1 "*) ;; + *) func_internal_error "invalid warning category '$1'" ;; + esac + + _G_category=$1 + shift + + case " $opt_warning_types " in + *" $_G_category "*) $warning_func ${1+"$@"} ;; + esac +} + + +# func_sort_ver VER1 VER2 +# ----------------------- +# 'sort -V' is not generally available. +# Note this deviates from the version comparison in automake +# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a +# but this should suffice as we won't be specifying old +# version formats or redundant trailing .0 in bootstrap.conf. +# If we did want full compatibility then we should probably +# use m4_version_compare from autoconf. +func_sort_ver () +{ + $debug_cmd + + printf '%s\n%s\n' "$1" "$2" \ + | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n +} + +# func_lt_ver PREV CURR +# --------------------- +# Return true if PREV and CURR are in the correct order according to +# func_sort_ver, otherwise false. Use it like this: +# +# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." +func_lt_ver () +{ + $debug_cmd + + test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: +#! /bin/sh + +# Set a version string for this script. +scriptversion=2014-01-07.03; # UTC + +# A portable, pluggable option parser for Bourne shell. +# Written by Gary V. Vaughan, 2010 + +# Copyright (C) 2010-2015 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# 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 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Please report bugs or propose patches to gary@gnu.org. + + +## ------ ## +## Usage. ## +## ------ ## + +# This file is a library for parsing options in your shell scripts along +# with assorted other useful supporting features that you can make use +# of too. +# +# For the simplest scripts you might need only: +# +# #!/bin/sh +# . relative/path/to/funclib.sh +# . relative/path/to/options-parser +# scriptversion=1.0 +# func_options ${1+"$@"} +# eval set dummy "$func_options_result"; shift +# ...rest of your script... +# +# In order for the '--version' option to work, you will need to have a +# suitably formatted comment like the one at the top of this file +# starting with '# Written by ' and ending with '# warranty; '. +# +# For '-h' and '--help' to work, you will also need a one line +# description of your script's purpose in a comment directly above the +# '# Written by ' line, like the one at the top of this file. +# +# The default options also support '--debug', which will turn on shell +# execution tracing (see the comment above debug_cmd below for another +# use), and '--verbose' and the func_verbose function to allow your script +# to display verbose messages only when your user has specified +# '--verbose'. +# +# After sourcing this file, you can plug processing for additional +# options by amending the variables from the 'Configuration' section +# below, and following the instructions in the 'Option parsing' +# section further down. + +## -------------- ## +## Configuration. ## +## -------------- ## + +# You should override these variables in your script after sourcing this +# file so that they reflect the customisations you have added to the +# option parser. + +# The usage line for option parsing errors and the start of '-h' and +# '--help' output messages. You can embed shell variables for delayed +# expansion at the time the message is displayed, but you will need to +# quote other shell meta-characters carefully to prevent them being +# expanded when the contents are evaled. +usage='$progpath [OPTION]...' + +# Short help message in response to '-h' and '--help'. Add to this or +# override it after sourcing this library to reflect the full set of +# options your script accepts. +usage_message="\ + --debug enable verbose shell tracing + -W, --warnings=CATEGORY + report the warnings falling in CATEGORY [all] + -v, --verbose verbosely report processing + --version print version information and exit + -h, --help print short or long help message and exit +" + +# Additional text appended to 'usage_message' in response to '--help'. +long_help_message=" +Warning categories include: + 'all' show all warnings + 'none' turn off all the warnings + 'error' warnings are treated as fatal errors" + +# Help message printed before fatal option parsing errors. +fatal_help="Try '\$progname --help' for more information." + + + +## ------------------------- ## +## Hook function management. ## +## ------------------------- ## + +# This section contains functions for adding, removing, and running hooks +# to the main code. A hook is just a named list of of function, that can +# be run in order later on. + +# func_hookable FUNC_NAME +# ----------------------- +# Declare that FUNC_NAME will run hooks added with +# 'func_add_hook FUNC_NAME ...'. +func_hookable () +{ + $debug_cmd + + func_append hookable_fns " $1" +} + + +# func_add_hook FUNC_NAME HOOK_FUNC +# --------------------------------- +# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must +# first have been declared "hookable" by a call to 'func_hookable'. +func_add_hook () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not accept hook functions." ;; + esac + + eval func_append ${1}_hooks '" $2"' +} + + +# func_remove_hook FUNC_NAME HOOK_FUNC +# ------------------------------------ +# Remove HOOK_FUNC from the list of functions called by FUNC_NAME. +func_remove_hook () +{ + $debug_cmd + + eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' +} + + +# func_run_hooks FUNC_NAME [ARG]... +# --------------------------------- +# Run all hook functions registered to FUNC_NAME. +# It is assumed that the list of hook functions contains nothing more +# than a whitespace-delimited list of legal shell function names, and +# no effort is wasted trying to catch shell meta-characters or preserve +# whitespace. +func_run_hooks () +{ + $debug_cmd + + case " $hookable_fns " in + *" $1 "*) ;; + *) func_fatal_error "'$1' does not support hook funcions.n" ;; + esac + + eval _G_hook_fns=\$$1_hooks; shift + + for _G_hook in $_G_hook_fns; do + eval $_G_hook '"$@"' + + # store returned options list back into positional + # parameters for next 'cmd' execution. + eval _G_hook_result=\$${_G_hook}_result + eval set dummy "$_G_hook_result"; shift + done + + func_quote_for_eval ${1+"$@"} + func_run_hooks_result=$func_quote_for_eval_result +} + + + +## --------------- ## +## Option parsing. ## +## --------------- ## + +# In order to add your own option parsing hooks, you must accept the +# full positional parameter list in your hook function, remove any +# options that you action, and then pass back the remaining unprocessed +# options in '_result', escaped suitably for +# 'eval'. Like this: +# +# my_options_prep () +# { +# $debug_cmd +# +# # Extend the existing usage message. +# usage_message=$usage_message' +# -s, --silent don'\''t print informational messages +# ' +# +# func_quote_for_eval ${1+"$@"} +# my_options_prep_result=$func_quote_for_eval_result +# } +# func_add_hook func_options_prep my_options_prep +# +# +# my_silent_option () +# { +# $debug_cmd +# +# # Note that for efficiency, we parse as many options as we can +# # recognise in a loop before passing the remainder back to the +# # caller on the first unrecognised argument we encounter. +# while test $# -gt 0; do +# opt=$1; shift +# case $opt in +# --silent|-s) opt_silent=: ;; +# # Separate non-argument short options: +# -s*) func_split_short_opt "$_G_opt" +# set dummy "$func_split_short_opt_name" \ +# "-$func_split_short_opt_arg" ${1+"$@"} +# shift +# ;; +# *) set dummy "$_G_opt" "$*"; shift; break ;; +# esac +# done +# +# func_quote_for_eval ${1+"$@"} +# my_silent_option_result=$func_quote_for_eval_result +# } +# func_add_hook func_parse_options my_silent_option +# +# +# my_option_validation () +# { +# $debug_cmd +# +# $opt_silent && $opt_verbose && func_fatal_help "\ +# '--silent' and '--verbose' options are mutually exclusive." +# +# func_quote_for_eval ${1+"$@"} +# my_option_validation_result=$func_quote_for_eval_result +# } +# func_add_hook func_validate_options my_option_validation +# +# You'll alse need to manually amend $usage_message to reflect the extra +# options you parse. It's preferable to append if you can, so that +# multiple option parsing hooks can be added safely. + + +# func_options [ARG]... +# --------------------- +# All the functions called inside func_options are hookable. See the +# individual implementations for details. +func_hookable func_options +func_options () +{ + $debug_cmd + + func_options_prep ${1+"$@"} + eval func_parse_options \ + ${func_options_prep_result+"$func_options_prep_result"} + eval func_validate_options \ + ${func_parse_options_result+"$func_parse_options_result"} + + eval func_run_hooks func_options \ + ${func_validate_options_result+"$func_validate_options_result"} + + # save modified positional parameters for caller + func_options_result=$func_run_hooks_result +} + + +# func_options_prep [ARG]... +# -------------------------- +# All initialisations required before starting the option parse loop. +# Note that when calling hook functions, we pass through the list of +# positional parameters. If a hook function modifies that list, and +# needs to propogate that back to rest of this script, then the complete +# modified list must be put in 'func_run_hooks_result' before +# returning. +func_hookable func_options_prep +func_options_prep () +{ + $debug_cmd + + # Option defaults: + opt_verbose=false + opt_warning_types= + + func_run_hooks func_options_prep ${1+"$@"} + + # save modified positional parameters for caller + func_options_prep_result=$func_run_hooks_result +} + + +# func_parse_options [ARG]... +# --------------------------- +# The main option parsing loop. +func_hookable func_parse_options +func_parse_options () +{ + $debug_cmd + + func_parse_options_result= + + # this just eases exit handling + while test $# -gt 0; do + # Defer to hook functions for initial option parsing, so they + # get priority in the event of reusing an option name. + func_run_hooks func_parse_options ${1+"$@"} + + # Adjust func_parse_options positional parameters to match + eval set dummy "$func_run_hooks_result"; shift + + # Break out of the loop if we already parsed every option. + test $# -gt 0 || break + + _G_opt=$1 + shift + case $_G_opt in + --debug|-x) debug_cmd='set -x' + func_echo "enabling shell trace mode" + $debug_cmd + ;; + + --no-warnings|--no-warning|--no-warn) + set dummy --warnings none ${1+"$@"} + shift + ;; + + --warnings|--warning|-W) + test $# = 0 && func_missing_arg $_G_opt && break + case " $warning_categories $1" in + *" $1 "*) + # trailing space prevents matching last $1 above + func_append_uniq opt_warning_types " $1" + ;; + *all) + opt_warning_types=$warning_categories + ;; + *none) + opt_warning_types=none + warning_func=: + ;; + *error) + opt_warning_types=$warning_categories + warning_func=func_fatal_error + ;; + *) + func_fatal_error \ + "unsupported warning category: '$1'" + ;; + esac + shift + ;; + + --verbose|-v) opt_verbose=: ;; + --version) func_version ;; + -\?|-h) func_usage ;; + --help) func_help ;; + + # Separate optargs to long options (plugins may need this): + --*=*) func_split_equals "$_G_opt" + set dummy "$func_split_equals_lhs" \ + "$func_split_equals_rhs" ${1+"$@"} + shift + ;; + + # Separate optargs to short options: + -W*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-v*|-x*) + func_split_short_opt "$_G_opt" + set dummy "$func_split_short_opt_name" \ + "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; + *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + esac + done + + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + func_parse_options_result=$func_quote_for_eval_result +} + + +# func_validate_options [ARG]... +# ------------------------------ +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +func_hookable func_validate_options +func_validate_options () +{ + $debug_cmd + + # Display all warnings if -W was not given. + test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" + + func_run_hooks func_validate_options ${1+"$@"} + + # Bail if the options were screwed! + $exit_cmd $EXIT_FAILURE + + # save modified positional parameters for caller + func_validate_options_result=$func_run_hooks_result +} + + + +## ----------------- ## +## Helper functions. ## +## ----------------- ## + +# This section contains the helper functions used by the rest of the +# hookable option parser framework in ascii-betical order. + + +# func_fatal_help ARG... +# ---------------------- +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + eval \$ECHO \""$fatal_help"\" + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + + +# func_help +# --------- +# Echo long help message to standard output and exit. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message" + exit 0 +} + + +# func_missing_arg ARGNAME +# ------------------------ +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $debug_cmd + + func_error "Missing argument for '$1'." + exit_cmd=exit +} + + +# func_split_equals STRING +# ------------------------ +# Set func_split_equals_lhs and func_split_equals_rhs shell variables after +# splitting STRING at the '=' sign. +test -z "$_G_HAVE_XSI_OPS" \ + && (eval 'x=a/b/c; + test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ + && _G_HAVE_XSI_OPS=yes + +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=${1%%=*} + func_split_equals_rhs=${1#*=} + test "x$func_split_equals_lhs" = "x$1" \ + && func_split_equals_rhs= + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_equals () + { + $debug_cmd + + func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` + func_split_equals_rhs= + test "x$func_split_equals_lhs" = "x$1" \ + || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` + } +fi #func_split_equals + + +# func_split_short_opt SHORTOPT +# ----------------------------- +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +if test yes = "$_G_HAVE_XSI_OPS" +then + # This is an XSI compatible shell, allowing a faster implementation... + eval 'func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"} + }' +else + # ...otherwise fall back to using expr, which is often a shell builtin. + func_split_short_opt () + { + $debug_cmd + + func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` + func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` + } +fi #func_split_short_opt + + +# func_usage +# ---------- +# Echo short help message to standard output and exit. +func_usage () +{ + $debug_cmd + + func_usage_message + $ECHO "Run '$progname --help |${PAGER-more}' for full usage" + exit 0 +} + + +# func_usage_message +# ------------------ +# Echo short help message to standard output. +func_usage_message () +{ + $debug_cmd + + eval \$ECHO \""Usage: $usage"\" + echo + $SED -n 's|^# || + /^Written by/{ + x;p;x + } + h + /^Written by/q' < "$progpath" + echo + eval \$ECHO \""$usage_message"\" +} + + +# func_version +# ------------ +# Echo version message to standard output and exit. +func_version () +{ + $debug_cmd + + printf '%s\n' "$progname $scriptversion" + $SED -n ' + /(C)/!b go + :more + /\./!{ + N + s|\n# | | + b more + } + :go + /^# Written by /,/# warranty; / { + s|^# || + s|^# *$|| + s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| + p + } + /^# Written by / { + s|^# || + p + } + /^warranty; /q' < "$progpath" + + exit $? +} + + +# Local variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-time-zone: "UTC" +# End: + +# Set a version string. +scriptversion='(GNU libtool) 2.4.6' + + +# func_echo ARG... +# ---------------- +# Libtool also displays the current mode in messages, so override +# funclib.sh func_echo with this custom definition. +func_echo () +{ + $debug_cmd + + _G_message=$* + + func_echo_IFS=$IFS + IFS=$nl + for _G_line in $_G_message; do + IFS=$func_echo_IFS + $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" + done + IFS=$func_echo_IFS +} + + +# func_warning ARG... +# ------------------- +# Libtool warnings are not categorized, so override funclib.sh +# func_warning with this simpler definition. +func_warning () +{ + $debug_cmd + + $warning_func ${1+"$@"} +} + + +## ---------------- ## +## Options parsing. ## +## ---------------- ## + +# Hook in the functions to make sure our own options are parsed during +# the option parsing loop. + +usage='$progpath [OPTION]... [MODE-ARG]...' + +# Short help message in response to '-h'. +usage_message="Options: + --config show all configuration variables + --debug enable verbose shell tracing + -n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --mode=MODE use operation mode MODE + --no-warnings equivalent to '-Wnone' + --preserve-dup-deps don't remove duplicate dependency libraries + --quiet, --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + -v, --verbose print more informational messages than default + --version print version information + -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] + -h, --help, --help-all print short, long, or detailed help message +" + +# Additional text appended to 'usage_message' in response to '--help'. +func_help () +{ + $debug_cmd + + func_usage_message + $ECHO "$long_help_message + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. When passed as first option, +'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. +Try '$progname --help --mode=MODE' for a more detailed description of MODE. + +When reporting a bug, please describe a test case to reproduce it and +include the following information: + + host-triplet: $host + shell: $SHELL + compiler: $LTCC + compiler flags: $LTCFLAGS + linker: $LD (gnu? $with_gnu_ld) + version: $progname (GNU libtool) 2.4.6 + automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` + autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` + +Report bugs to . +GNU libtool home page: . +General help using GNU software: ." + exit 0 +} + + +# func_lo2o OBJECT-NAME +# --------------------- +# Transform OBJECT-NAME from a '.lo' suffix to the platform specific +# object suffix. + +lo2o=s/\\.lo\$/.$objext/ +o2lo=s/\\.$objext\$/.lo/ + +if test yes = "$_G_HAVE_XSI_OPS"; then + eval 'func_lo2o () + { + case $1 in + *.lo) func_lo2o_result=${1%.lo}.$objext ;; + * ) func_lo2o_result=$1 ;; + esac + }' + + # func_xform LIBOBJ-OR-SOURCE + # --------------------------- + # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) + # suffix to a '.lo' libtool-object suffix. + eval 'func_xform () + { + func_xform_result=${1%.*}.lo + }' +else + # ...otherwise fall back to using sed. + func_lo2o () + { + func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` + } + + func_xform () + { + func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` + } +fi + + +# func_fatal_configuration ARG... +# ------------------------------- +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_fatal_error ${1+"$@"} \ + "See the $PACKAGE documentation for more information." \ + "Fatal configuration error." +} + + +# func_config +# ----------- +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + + +# func_features +# ------------- +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test yes = "$build_libtool_libs"; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test yes = "$build_old_libs"; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + + +# func_enable_tag TAGNAME +# ----------------------- +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname=$1 + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf=/$re_begincf/,/$re_endcf/p + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + + +# func_check_version_match +# ------------------------ +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# libtool_options_prep [ARG]... +# ----------------------------- +# Preparation for options parsed by libtool. +libtool_options_prep () +{ + $debug_mode + + # Option defaults: + opt_config=false + opt_dlopen= + opt_dry_run=false + opt_help=false + opt_mode= + opt_preserve_dup_deps=false + opt_quiet=false + + nonopt= + preserve_args= + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Pass back the list of options. + func_quote_for_eval ${1+"$@"} + libtool_options_prep_result=$func_quote_for_eval_result +} +func_add_hook func_options_prep libtool_options_prep + + +# libtool_parse_options [ARG]... +# --------------------------------- +# Provide handling for libtool specific options. +libtool_parse_options () +{ + $debug_cmd + + # Perform our own loop to consume as many options as possible in + # each iteration. + while test $# -gt 0; do + _G_opt=$1 + shift + case $_G_opt in + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + + --config) func_config ;; + + --dlopen|-dlopen) + opt_dlopen="${opt_dlopen+$opt_dlopen +}$1" + shift + ;; + + --preserve-dup-deps) + opt_preserve_dup_deps=: ;; + + --features) func_features ;; + + --finish) set dummy --mode finish ${1+"$@"}; shift ;; + + --help) opt_help=: ;; + + --help-all) opt_help=': help-all' ;; + + --mode) test $# = 0 && func_missing_arg $_G_opt && break + opt_mode=$1 + case $1 in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $_G_opt" + exit_cmd=exit + break + ;; + esac + shift + ;; + + --no-silent|--no-quiet) + opt_quiet=false + func_append preserve_args " $_G_opt" + ;; + + --no-warnings|--no-warning|--no-warn) + opt_warning=false + func_append preserve_args " $_G_opt" + ;; + + --no-verbose) + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --silent|--quiet) + opt_quiet=: + opt_verbose=false + func_append preserve_args " $_G_opt" + ;; + + --tag) test $# = 0 && func_missing_arg $_G_opt && break + opt_tag=$1 + func_append preserve_args " $_G_opt $1" + func_enable_tag "$1" + shift + ;; + + --verbose|-v) opt_quiet=false + opt_verbose=: + func_append preserve_args " $_G_opt" + ;; + + # An option not handled by this hook function: + *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + esac + done + + + # save modified positional parameters for caller + func_quote_for_eval ${1+"$@"} + libtool_parse_options_result=$func_quote_for_eval_result +} +func_add_hook func_parse_options libtool_parse_options + + + +# libtool_validate_options [ARG]... +# --------------------------------- +# Perform any sanity checks on option settings and/or unconsumed +# arguments. +libtool_validate_options () +{ + # save first non-option argument + if test 0 -lt $#; then + nonopt=$1 + shift + fi + + # preserve --debug + test : = "$debug_cmd" || func_append preserve_args " --debug" + + case $host in + # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 + # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 + *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + test yes != "$build_libtool_libs" \ + && test yes != "$build_old_libs" \ + && func_fatal_configuration "not configured to build any kind of library" + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test execute != "$opt_mode"; then + func_error "unrecognized option '-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help=$help + help="Try '$progname --help --mode=$opt_mode' for more information." + } + + # Pass back the unparsed argument list + func_quote_for_eval ${1+"$@"} + libtool_validate_options_result=$func_quote_for_eval_result +} +func_add_hook func_validate_options libtool_validate_options + + +# Process options as early as possible so that --help and --version +# can return quickly. +func_options ${1+"$@"} +eval set dummy "$func_options_result"; shift + + + +## ----------- ## +## Main. ## +## ----------- ## + +magic='%%%MAGIC variable%%%' +magic_exe='%%%MAGIC EXE variable%%%' + +# Global variables. +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# func_generated_by_libtool +# True iff stdin has been generated by Libtool. This function is only +# a basic sanity check; it will hardly flush out determined imposters. +func_generated_by_libtool_p () +{ + $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_p file +# True iff FILE is a libtool '.la' library or '.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool '.la' library or '.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if 'file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case $lalib_p_line in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test yes = "$lalib_p" +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + test -f "$1" && + $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $debug_cmd + + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# 'FILE.' does not work on cygwin managed mounts. +func_source () +{ + $debug_cmd + + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case $lt_sysroot:$1 in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result='='$func_stripname_result + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $debug_cmd + + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with '--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=$1 + if test yes = "$build_libtool_libs"; then + write_lobj=\'$2\' + else + write_lobj=none + fi + + if test yes = "$build_old_libs"; then + write_oldobj=\'$3\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $debug_cmd + + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result= + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result"; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $debug_cmd + + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $debug_cmd + + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $debug_cmd + + if test -z "$2" && test -n "$1"; then + func_error "Could not determine host file name corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result=$1 + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $debug_cmd + + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " '$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result=$3 + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $debug_cmd + + case $4 in + $1 ) func_to_host_path_result=$3$func_to_host_path_result + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via '$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $debug_cmd + + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $debug_cmd + + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result=$1 +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result=$func_convert_core_msys_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result=$func_convert_core_file_wine_to_w32_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_file_result=$1 + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result=$func_cygpath_result + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via '$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $debug_cmd + + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd=func_convert_path_$func_stripname_result + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $debug_cmd + + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result=$1 +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_msys_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result=$func_convert_core_path_wine_to_w32_result + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $debug_cmd + + func_to_host_path_result=$1 + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result=$func_cygpath_result + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_dll_def_p FILE +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with _LT_DLL_DEF_P in libtool.m4 +func_dll_def_p () +{ + $debug_cmd + + func_dll_def_p_tmp=`$SED -n \ + -e 's/^[ ]*//' \ + -e '/^\(;.*\)*$/d' \ + -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ + -e q \ + "$1"` + test DEF = "$func_dll_def_p_tmp" +} + + +# func_mode_compile arg... +func_mode_compile () +{ + $debug_cmd + + # Get the compilation command and the source file. + base_compile= + srcfile=$nonopt # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg=$arg + arg_mode=normal + ;; + + target ) + libobj=$arg + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify '-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs=$IFS; IFS=, + for arg in $args; do + IFS=$save_ifs + func_append_quoted lastarg "$arg" + done + IFS=$save_ifs + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg=$srcfile + srcfile=$arg + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with '-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj=$func_basename_result + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from '$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test yes = "$build_libtool_libs" \ + || func_fatal_configuration "cannot build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name '$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname=$func_basename_result + xdir=$func_dirname_result + lobj=$xdir$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test yes = "$build_old_libs"; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test no = "$compiler_c_o"; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext + lockfile=$output_obj.lock + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test yes = "$need_locks"; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test warn = "$need_locks"; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support '-c' and '-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test yes = "$build_libtool_libs"; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test no != "$pic_mode"; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support '-c' and '-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test yes = "$suppress_opt"; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test yes = "$build_old_libs"; then + if test yes != "$pic_mode"; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test yes = "$compiler_c_o"; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test warn = "$need_locks" && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support '-c' and '-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test no != "$need_locks"; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test compile = "$opt_mode" && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a '.o' file suitable for static linking + -static only build a '.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a 'standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix '.c' with the +library object suffix, '.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to '-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the '--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the 'install' or 'cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE use a list of object files found in FILE to specify objects + -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with '-') are ignored. + +Every other argument is treated as a filename. Files ending in '.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in '.la', then a libtool library is created, +only library objects ('.lo' files) may be specified, and '-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created +using 'ar' and 'ranlib', or on Windows using 'lib'. + +If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode '$opt_mode'" + ;; + esac + + echo + $ECHO "Try '$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test : = "$opt_help"; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | $SED -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + $SED '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $debug_cmd + + # The first argument is the command name. + cmd=$nonopt + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "'$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "'$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "'$file' was not linked with '-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir=$func_dirname_result + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir=$func_dirname_result + ;; + + *) + func_warning "'-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir=$absdir + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic=$magic + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file=$progdir/$program + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file=$progdir/$program + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if $opt_dry_run; then + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + else + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd=\$cmd$args + fi +} + +test execute = "$opt_mode" && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $debug_cmd + + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "'$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument '$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and '=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_quiet && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the '-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the '$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the '$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the '$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test finish = "$opt_mode" && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $debug_cmd + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac + then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=false + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=: ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test X-m = "X$prev" && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the '$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=: + if $isdir; then + destdir=$dest + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir=$func_dirname_result + destname=$func_basename_result + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "'$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "'$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic=$magic + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "'$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir=$func_dirname_result + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking '$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname=$1 + shift + + srcname=$realname + test -n "$relink_command" && srcname=${realname}T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme=$stripme + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme= + ;; + esac + ;; + os2*) + case $realname in + *_dll.a) + tstripme= + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try 'ln -sf' first, because the 'ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib=$destdir/$realname + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name=$func_basename_result + instname=$dir/${name}i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile=$destdir/$destname + else + func_basename "$file" + destfile=$func_basename_result + destfile=$destdir/$destfile + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest=$destfile + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to '$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test yes = "$build_old_libs"; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile=$destdir/$destname + else + func_basename "$file" + destfile=$func_basename_result + destfile=$destdir/$destfile + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext= + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=.exe + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script '$wrapper'" + + finalize=: + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "'$lib' has not been installed in '$libdir'" + finalize=false + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test no = "$fast_install" && test -n "$relink_command"; then + $opt_dry_run || { + if $finalize; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file=$func_basename_result + outputname=$tmpdir/$file + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_quiet || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink '$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file=$outputname + else + func_warning "cannot relink '$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name=$func_basename_result + + # Set up the ranlib parameters. + oldlib=$destdir/$name + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run '$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test install = "$opt_mode" && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $debug_cmd + + my_outputname=$1 + my_originator=$2 + my_pic_p=${3-false} + my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms=${my_outputname}S.c + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist=$output_objdir/$my_outputname.nm + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* External symbol declarations for the compiler. */\ +" + + if test yes = "$dlself"; then + func_verbose "generating symbol list for '$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from '$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols=$output_objdir/$outputname.exp + $opt_dry_run || { + $RM $export_symbols + eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from '$dlprefile'" + func_basename "$dlprefile" + name=$func_basename_result + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename= + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname"; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename=$func_basename_result + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename"; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + func_show_eval '$RM "${nlist}I"' + if test -n "$global_symbol_to_import"; then + eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[];\ +" + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ +static void lt_syminit(void) +{ + LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; + for (; symbol->name; ++symbol) + {" + $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" + echo >> "$output_objdir/$my_dlsyms" "\ + } +}" + fi + echo >> "$output_objdir/$my_dlsyms" "\ +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{ {\"$my_originator\", (void *) 0}," + + if test -s "$nlist"I; then + echo >> "$output_objdir/$my_dlsyms" "\ + {\"@INIT@\", (void *) <_syminit}," + fi + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + $my_pic_p && pic_flag_for_symtable=" $pic_flag" + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' + + # Transform the symbol file into the correct name. + symfileobj=$output_objdir/${my_outputname}S.$objext + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for '$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $debug_cmd + + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $debug_cmd + + win32_libid_type=unknown + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + case $nm_interface in + "MS dumpbin") + if func_cygming_ms_implib_p "$1" || + func_cygming_gnu_implib_p "$1" + then + win32_nmres=import + else + win32_nmres= + fi + ;; + *) + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s|.*|import| + p + q + } + }'` + ;; + esac + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $debug_cmd + + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $debug_cmd + + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive that possess that section. Heuristic: eliminate + # all those that have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $debug_cmd + + if func_cygming_gnu_implib_p "$1"; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1"; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result= + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $debug_cmd + + f_ex_an_ar_dir=$1; shift + f_ex_an_ar_oldlib=$1 + if test yes = "$lock_old_archive_extraction"; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test yes = "$lock_old_archive_extraction"; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $debug_cmd + + my_gentop=$1; shift + my_oldlibs=${1+"$@"} + my_oldobjs= + my_xlib= + my_xabs= + my_xdir= + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib=$func_basename_result + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir=$my_gentop/$my_xlib_u + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + func_basename "$darwin_archive" + darwin_base_archive=$func_basename_result + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches; do + func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" + $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" + cd "unfat-$$/$darwin_base_archive-$darwin_arch" + func_extract_an_archive "`pwd`" "$darwin_base_archive" + cd "$darwin_curdir" + $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result=$my_oldobjs +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory where it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ that is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options that match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test yes = "$fast_install"; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + \$ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) + +/* declarations of non-ANSI functions */ +#if defined __MINGW32__ +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined __CYGWIN__ +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined other_platform || defined ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined _MSC_VER +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +#elif defined __MINGW32__ +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined __CYGWIN__ +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined other platforms ... */ +#endif + +#if defined PATH_MAX +# define LT_PATHMAX PATH_MAX +#elif defined MAXPATHLEN +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ + defined __OS2__ +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free (stale); stale = 0; } \ +} while (0) + +#if defined LT_DEBUGWRAPPER +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + size_t tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined HAVE_DOS_BASED_FILE_SYSTEM + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined HAVE_DOS_BASED_FILE_SYSTEM + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = (size_t) (q - p); + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (STREQ (str, pat)) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + size_t len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + size_t orig_value_len = strlen (orig_value); + size_t add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + size_t len = strlen (new_value); + while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[--len] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $debug_cmd + + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_suncc_cstd_abi +# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! +# Several compiler flags select an ABI that is incompatible with the +# Cstd library. Avoid specifying it if any are in CXXFLAGS. +func_suncc_cstd_abi () +{ + $debug_cmd + + case " $compile_command " in + *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) + suncc_use_cstd_abi=no + ;; + *) + suncc_use_cstd_abi=yes + ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $debug_cmd + + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # what system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll that has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + os2dllname= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=false + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module=$wl-single_module + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test yes != "$build_libtool_libs" \ + && func_fatal_configuration "cannot build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg=$1 + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir=$arg + prev= + continue + ;; + dlfiles|dlprefiles) + $preload || { + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=: + } + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test no = "$dlself"; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test dlprefiles = "$prev"; then + dlself=yes + elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test dlfiles = "$prev"; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols=$arg + test -f "$arg" \ + || func_fatal_error "symbol file '$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex=$arg + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir=$arg + prev= + continue + ;; + mllvm) + # Clang does not use LLVM to link, so we can simply discard any + # '-mllvm $arg' options when doing the link step. + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + if test none != "$pic_object"; then + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + fi + + # Non-PIC object. + if test none != "$non_pic_object"; then + # Prepend the subdirectory the object is found in. + non_pic_object=$xdir$non_pic_object + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test none = "$pic_object"; then + arg=$non_pic_object + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object=$pic_object + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "'$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file '$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + os2dllname) + os2dllname=$arg + prev= + continue + ;; + precious_regex) + precious_files_regex=$arg + prev= + continue + ;; + release) + release=-$arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test rpath = "$prev"; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds=$arg + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg=$arg + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "'-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test X-export-symbols = "X$arg"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between '-L' and '$1'" + else + func_fatal_error "need path for '-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of '$dir'" + dir=$absdir + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test X-lc = "X$arg" || test X-lm = "X$arg"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test X-lc = "X$arg" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + # Do not include libc due to us having libc/libc_r. + test X-lc = "X$arg" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test X-lc = "X$arg" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test X-lc = "X$arg" && continue + ;; + esac + elif test X-lc_r = "X$arg"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -mllvm) + prev=mllvm + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module=$wl-multi_module + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "'-no-install' is ignored for $host" + func_warning "assuming '-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -os2dllname) + prev=os2dllname + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs=$IFS; IFS=, + for flag in $args; do + IFS=$save_ifs + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS=$save_ifs + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs=$IFS; IFS=, + for flag in $args; do + IFS=$save_ifs + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS=$save_ifs + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # -fstack-protector* stack protector flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + # -specs=* GCC specs files + # -stdlib=* select c++ std lib with clang + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ + -specs=*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + -Z*) + if test os2 = "`expr $host : '.*\(os2\)'`"; then + # OS/2 uses -Zxxx to specify OS/2-specific options + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case $arg in + -Zlinker | -Zstack) + prev=xcompiler + ;; + esac + continue + else + # Otherwise treat like 'Some other compiler flag' below + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + fi + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test none = "$pic_object" && + test none = "$non_pic_object"; then + func_fatal_error "cannot find name of object for '$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + test none = "$pic_object" || { + # Prepend the subdirectory the object is found in. + pic_object=$xdir$pic_object + + if test dlfiles = "$prev"; then + if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test dlprefiles = "$prev"; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg=$pic_object + } + + # Non-PIC object. + if test none != "$non_pic_object"; then + # Prepend the subdirectory the object is found in. + non_pic_object=$xdir$non_pic_object + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test none = "$pic_object"; then + arg=$non_pic_object + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object=$pic_object + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir=$func_dirname_result + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "'$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test dlfiles = "$prev"; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test dlprefiles = "$prev"; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg=$func_quote_for_eval_result + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the '$prevarg' option requires an argument" + + if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname=$func_basename_result + libobjs_save=$libobjs + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + # Definition is injected by LT_CONFIG during libtool generation. + func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" + + func_dirname "$output" "/" "" + output_objdir=$func_dirname_result$objdir + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test lib = "$linkmode"; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=false + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test lib,link = "$linkmode,$pass"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs=$tmp_deplibs + fi + + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass"; then + libs=$deplibs + deplibs= + fi + if test prog = "$linkmode"; then + case $pass in + dlopen) libs=$dlfiles ;; + dlpreopen) libs=$dlprefiles ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test lib,dlpreopen = "$linkmode,$pass"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs=$dlprefiles + fi + if test dlopen = "$pass"; then + # Collect dlpreopened libraries + save_deplibs=$deplibs + deplibs= + fi + + for deplib in $libs; do + lib= + found=false + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test lib != "$linkmode" && test prog != "$linkmode"; then + func_warning "'-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test lib = "$linkmode"; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib=$searchdir/lib$name$search_ext + if test -f "$lib"; then + if test .la = "$search_ext"; then + found=: + else + found=false + fi + break 2 + fi + done + done + if $found; then + # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll=$l + done + if test "X$ll" = "X$old_library"; then # only static version available + found=false + func_dirname "$lib" "" "." + ladir=$func_dirname_result + lib=$ladir/$old_library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + else + # deplib doesn't seem to be a libtool library + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + ;; # -l + *.ltframework) + if test prog,link = "$linkmode,$pass"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test lib = "$linkmode"; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test conv = "$pass" && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + if test scan = "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "'-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test link = "$pass"; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=false + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=: + fi + ;; + pass_all) + valid_a_lib=: + ;; + esac + if $valid_a_lib; then + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + else + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + fi + ;; + esac + continue + ;; + prog) + if test link != "$pass"; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test conv = "$pass"; then + deplibs="$deplib $deplibs" + elif test prog = "$linkmode"; then + if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=: + continue + ;; + esac # case $deplib + + $found || test -f "$lib" \ + || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "'$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir=$func_dirname_result + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test lib,link = "$linkmode,$pass" || + test prog,scan = "$linkmode,$pass" || + { test prog != "$linkmode" && test lib != "$linkmode"; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test conv = "$pass"; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for '$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + elif test prog != "$linkmode" && test lib != "$linkmode"; then + func_fatal_error "'$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test yes = "$prefer_static_libs" || + test built,no = "$prefer_static_libs,$installed"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib=$l + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for '$lib'" + fi + + # This library was specified with -dlopen. + if test dlopen = "$pass"; then + test -z "$libdir" \ + && func_fatal_error "cannot -dlopen a convenience library: '$lib'" + if test -z "$dlname" || + test yes != "$dlopen_support" || + test no = "$build_libtool_libs" + then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of '$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir=$ladir + fi + ;; + esac + func_basename "$lib" + laname=$func_basename_result + + # Find the relevant object directory and library name. + if test yes = "$installed"; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library '$lib' was moved." + dir=$ladir + absdir=$abs_ladir + libdir=$abs_ladir + else + dir=$lt_sysroot$libdir + absdir=$lt_sysroot$libdir + fi + test yes = "$hardcode_automatic" && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir=$ladir + absdir=$abs_ladir + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir=$ladir/$objdir + absdir=$abs_ladir/$objdir + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test dlpreopen = "$pass"; then + if test -z "$libdir" && test prog = "$linkmode"; then + func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" + fi + case $host in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test lib = "$linkmode"; then + deplibs="$dir/$old_library $deplibs" + elif test prog,link = "$linkmode,$pass"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test prog = "$linkmode" && test link != "$pass"; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=false + if test no != "$link_all_deplibs" || test -z "$library_names" || + test no = "$build_libtool_libs"; then + linkalldeplibs=: + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if $linkalldeplibs; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test prog,link = "$linkmode,$pass"; then + if test -n "$library_names" && + { { test no = "$prefer_static_libs" || + test built,yes = "$prefer_static_libs,$installed"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then + # Make sure the rpath contains only unique directories. + case $temp_rpath: in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if $alldeplibs && + { test pass_all = "$deplibs_check_method" || + { test yes = "$build_libtool_libs" && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test built = "$use_static_libs" && test yes = "$installed"; then + use_static_libs=no + fi + if test -n "$library_names" && + { test no = "$use_static_libs" || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc* | *os2*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test no = "$installed"; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule= + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule=$dlpremoduletest + break + fi + done + if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then + echo + if test prog = "$linkmode"; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test lib = "$linkmode" && + test yes = "$hardcode_into_libs"; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname=$1 + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname=$dlname + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc* | *os2*) + func_arith $current - $age + major=$func_arith_result + versuffix=-$major + ;; + esac + eval soname=\"$soname_spec\" + else + soname=$realname + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot=$soname + func_basename "$soroot" + soname=$func_basename_result + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from '$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for '$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test prog = "$linkmode" || test relink != "$opt_mode"; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test no = "$hardcode_direct"; then + add=$dir/$linklib + case $host in + *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; + *-*-sysv4*uw2*) add_dir=-L$dir ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir=-L$dir ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we cannot + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library"; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add=$dir/$old_library + fi + elif test -n "$old_library"; then + add=$dir/$old_library + fi + fi + esac + elif test no = "$hardcode_minus_L"; then + case $host in + *-*-sunos*) add_shlibpath=$dir ;; + esac + add_dir=-L$dir + add=-l$name + elif test no = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + relink) + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$dir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$absdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + add_shlibpath=$dir + add=-l$name + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test yes != "$lib_linked"; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test prog = "$linkmode"; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test yes != "$hardcode_direct" && + test yes != "$hardcode_minus_L" && + test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test prog = "$linkmode" || test relink = "$opt_mode"; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test yes = "$hardcode_direct" && + test no = "$hardcode_direct_absolute"; then + add=$libdir/$linklib + elif test yes = "$hardcode_minus_L"; then + add_dir=-L$libdir + add=-l$name + elif test yes = "$hardcode_shlibpath_var"; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add=-l$name + elif test yes = "$hardcode_automatic"; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib"; then + add=$inst_prefix_dir$libdir/$linklib + else + add=$libdir/$linklib + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir=-L$libdir + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add=-l$name + fi + + if test prog = "$linkmode"; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test prog = "$linkmode"; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test unsupported != "$hardcode_direct"; then + test -n "$old_library" && linklib=$old_library + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test yes = "$build_libtool_libs"; then + # Not a shared library + if test pass_all != "$deplibs_check_method"; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system cannot link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test yes = "$module"; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using 'nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** 'nm' from GNU binutils and a full rebuild may help." + fi + if test no = "$build_old_libs"; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test lib = "$linkmode"; then + if test -n "$dependency_libs" && + { test yes != "$hardcode_into_libs" || + test yes = "$build_old_libs" || + test yes = "$link_static"; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs=$temp_deplibs + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test no != "$link_all_deplibs"; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path=$deplib ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of '$dir'" + absdir=$dir + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names"; then + for tmp in $deplibrary_names; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl"; then + depdepl=$absdir/$objdir/$depdepl + darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" + func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" + path= + fi + fi + ;; + *) + path=-L$absdir/$objdir + ;; + esac + else + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "'$deplib' seems to be moved" + + path=-L$absdir + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test link = "$pass"; then + if test prog = "$linkmode"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs=$newdependency_libs + if test dlpreopen = "$pass"; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test dlopen != "$pass"; then + test conv = "$pass" || { + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + } + + if test prog,link = "$linkmode,$pass"; then + vars="compile_deplibs finalize_deplibs" + else + vars=deplibs + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + + # Add Sun CC postdeps if required: + test CXX = "$tagname" && { + case $host_os in + linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C++ 5.9 + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + + solaris*) + func_cc_basename "$CC" + case $func_cc_basename_result in + CC* | sunCC*) + func_suncc_cstd_abi + + if test no != "$suncc_use_cstd_abi"; then + func_append postdeps ' -library=Cstd -library=Crun' + fi + ;; + esac + ;; + esac + } + + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i= + ;; + esac + if test -n "$i"; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test prog = "$linkmode"; then + dlfiles=$newdlfiles + fi + if test prog = "$linkmode" || test lib = "$linkmode"; then + dlprefiles=$newdlprefiles + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + func_warning "'-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "'-l' and '-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "'-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "'-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "'-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "'-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "'-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs=$output + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form 'libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test no = "$module" \ + && func_fatal_help "libtool library '$output' must begin with 'lib'" + + if test no != "$need_lib_prefix"; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test pass_all != "$deplibs_check_method"; then + func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test no = "$dlself" \ + || func_warning "'-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test 1 -lt "$#" \ + && func_warning "ignoring multiple '-rpath's for a libtool library" + + install_libdir=$1 + + oldlibs= + if test -z "$rpath"; then + if test yes = "$build_libtool_libs"; then + # Building a libtool convenience library. + # Some compilers have problems with a '.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "'-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "'-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs=$IFS; IFS=: + set dummy $vinfo 0 0 0 + shift + IFS=$save_ifs + + test -n "$7" && \ + func_fatal_help "too many parameters to '-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major=$1 + number_minor=$2 + number_revision=$3 + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # that has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|freebsd-elf|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_revision + ;; + freebsd-aout|qnx|sunos) + current=$number_major + revision=$number_minor + age=0 + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age=$number_minor + revision=$number_minor + lt_irix_increment=no + ;; + esac + ;; + no) + current=$1 + revision=$2 + age=$3 + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT '$current' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION '$revision' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE '$age' must be a nonnegative integer" + func_fatal_error "'$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE '$age' is greater than the current interface number '$current'" + func_fatal_error "'$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + # On Darwin other compilers + case $CC in + nagfor*) + verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" + ;; + *) + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + esac + ;; + + freebsd-aout) + major=.$current + versuffix=.$current.$revision + ;; + + freebsd-elf) + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + irix | nonstopux) + if test no = "$lt_irix_increment"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring=$verstring_prefix$major.$revision + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test 0 -ne "$loop"; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring=$verstring_prefix$major.$iface:$verstring + done + + # Before this point, $major must not contain '.'. + major=.$major + versuffix=$major.$revision + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix=$major.$age.$revision + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=.$current.$age.$revision + verstring=$current.$age.$revision + + # Add in all the interfaces that we are compatible with. + loop=$age + while test 0 -ne "$loop"; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring=$verstring:$iface.0 + done + + # Make executables depend on our current version. + func_append verstring ":$current.0" + ;; + + qnx) + major=.$current + versuffix=.$current + ;; + + sco) + major=.$current + versuffix=.$current + ;; + + sunos) + major=.$current + versuffix=.$current.$revision + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 file systems. + func_arith $current - $age + major=$func_arith_result + versuffix=-$major + ;; + + *) + func_fatal_configuration "unknown library version type '$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring=0.0 + ;; + esac + if test no = "$need_version"; then + versuffix= + else + versuffix=.0.0 + fi + fi + + # Remove version info from name if versioning should be avoided + if test yes,no = "$avoid_version,$need_version"; then + major= + versuffix= + verstring= + fi + + # Check to see if the archive will have undefined symbols. + if test yes = "$allow_undefined"; then + if test unsupported = "$allow_undefined_flag"; then + if test yes = "$build_old_libs"; then + func_warning "undefined symbols not allowed in $host shared libraries; building static only" + build_libtool_libs=no + else + func_fatal_error "can't build $host shared library unless -no-undefined is specified" + fi + fi + else + # Don't allow undefined symbols. + allow_undefined_flag=$no_undefined_flag + fi + + fi + + func_generate_dlsyms "$libname" "$libname" : + func_append libobjs " $symfileobj" + test " " = "$libobjs" && libobjs= + + if test relink != "$opt_mode"; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) + if test -n "$precious_files_regex"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles=$dlfiles + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles=$dlprefiles + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test yes = "$build_libtool_libs"; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test yes = "$build_libtool_need_lc"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release= + versuffix= + major= + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib=$potent_lib + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | $SED 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; + *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib= + break 2 + fi + done + done + fi + if test -n "$a_deplib"; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib"; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib= + ;; + esac + fi + if test -n "$a_deplib"; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib=$potent_lib # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib= + break 2 + fi + done + done + fi + if test -n "$a_deplib"; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib"; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs= + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test yes = "$allow_libtool_libs_with_static_runtimes"; then + for i in $predeps $postdeps; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test none = "$deplibs_check_method"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test yes = "$droppeddeps"; then + if test yes = "$module"; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using 'nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** 'nm' from GNU binutils and a full rebuild may help." + fi + if test no = "$build_old_libs"; then + oldlibs=$output_objdir/$libname.$libext + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test no = "$allow_undefined"; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test no = "$build_old_libs"; then + oldlibs=$output_objdir/$libname.$libext + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs=$new_libs + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test yes = "$build_libtool_libs"; then + # Remove $wl instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test yes = "$hardcode_into_libs"; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath=$finalize_rpath + test relink = "$opt_mode" || rpath=$compile_rpath$rpath + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs=$libdir + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir=$hardcode_libdirs + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath=$finalize_shlibpath + test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname=$1 + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname=$realname + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib=$output_objdir/$realname + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols=$output_objdir/$libname.uexp + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + func_dll_def_p "$export_symbols" || { + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols=$export_symbols + export_symbols= + always_export_symbols=yes + } + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for '$libname.la'" + export_symbols=$output_objdir/$libname.exp + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs=$IFS; IFS='~' + for cmd1 in $cmds; do + IFS=$save_ifs + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test yes = "$try_normal_branch" \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=$output_objdir/$output_la.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS=$save_ifs + if test -n "$export_symbols_regex" && test : != "$skipped_export"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols=$export_symbols + test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test : != "$skipped_export" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for '$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands, which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs=$tmp_deplibs + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test yes = "$compiler_needs_object" && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test relink = "$opt_mode"; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test yes = "$module" && test -n "$module_cmds"; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test : != "$skipped_export" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then + output=$output_objdir/$output_la.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then + output=$output_objdir/$output_la.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test yes = "$compiler_needs_object"; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-$k.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test -z "$objlist" || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test 1 -eq "$k"; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-$k.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-$k.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + ${skipped_export-false} && { + func_verbose "generating symbol list for '$libname.la'" + export_symbols=$output_objdir/$libname.exp + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + } + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs=$IFS; IFS='~' + for cmd in $concat_cmds; do + IFS=$save_ifs + $opt_quiet || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS=$save_ifs + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + ${skipped_export-false} && { + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols=$export_symbols + test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for '$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands, which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + } + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test yes = "$module" && test -n "$module_cmds"; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs=$IFS; IFS='~' + for cmd in $cmds; do + IFS=$sp$nl + eval cmd=\"$cmd\" + IFS=$save_ifs + $opt_quiet || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS=$save_ifs + + # Restore the uninstalled library and exit + if test relink = "$opt_mode"; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test yes = "$module" || test yes = "$export_dynamic"; then + # On all known operating systems, these are identical. + dlname=$soname + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then + func_warning "'-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "'-l' and '-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "'-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "'-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "'-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "'-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object '$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj=$output + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # if reload_cmds runs $LD directly, get rid of -Wl from + # whole_archive_flag_spec and hope we can get by with turning comma + # into space. + case $reload_cmds in + *\$LD[\ \$]*) wl= ;; + esac + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags + else + gentop=$output_objdir/${obj}x + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test yes = "$build_libtool_libs" || libobjs=$non_pic_objects + + # Create the old-style object. + reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs + + output=$obj + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + test yes = "$build_libtool_libs" || { + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + } + + if test -n "$pic_flag" || test default != "$pic_mode"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output=$libobj + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "'-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "'-release' is ignored for programs" + + $preload \ + && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ + && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test CXX = "$tagname"; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " $wl-bind_at_load" + func_append finalize_command " $wl-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs=$new_libs + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs=$libdir + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir=$hardcode_libdirs + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath=$rpath + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs=$libdir + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir=$hardcode_libdirs + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath=$rpath + + if test -n "$libobjs" && test yes = "$build_old_libs"; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" false + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=: + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=false + ;; + *cygwin* | *mingw* ) + test yes = "$build_libtool_libs" || wrappers_required=false + ;; + *) + if test no = "$need_relink" || test yes != "$build_libtool_libs"; then + wrappers_required=false + fi + ;; + esac + $wrappers_required || { + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command=$compile_command$compile_rpath + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.$objext"; then + func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' + fi + + exit $exit_status + } + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test yes = "$no_install"; then + # We don't need to create a wrapper script. + link_command=$compile_var$compile_command$compile_rpath + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + case $hardcode_action,$fast_install in + relink,*) + # Fast installation is not supported + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "'$output' will be relinked during installation" + ;; + *,yes) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + ;; + *,no) + link_command=$compile_var$compile_command$compile_rpath + relink_command=$finalize_var$finalize_command$finalize_rpath + ;; + *,needless) + link_command=$finalize_var$compile_command$finalize_rpath + relink_command= + ;; + esac + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource=$output_path/$objdir/lt-$output_name.c + cwrapper=$output_path/$output_name.exe + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host"; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + case $build_libtool_libs in + convenience) + oldobjs="$libobjs_save $symfileobj" + addlibs=$convenience + build_libtool_libs=no + ;; + module) + oldobjs=$libobjs_save + addlibs=$old_convenience + build_libtool_libs=no + ;; + *) + oldobjs="$old_deplibs $non_pic_objects" + $preload && test -f "$symfileobj" \ + && func_append oldobjs " $symfileobj" + addlibs=$old_convenience + ;; + esac + + if test -n "$addlibs"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop=$output_objdir/${outputname}x + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase=$func_basename_result + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj"; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test -z "$oldobjs"; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test yes = "$build_old_libs" && old_library=$libname.$libext + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test yes = "$hardcode_automatic"; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test yes = "$installed"; then + if test -z "$install_libdir"; then + break + fi + output=$output_objdir/${outputname}i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name=$func_basename_result + func_resolve_sysroot "$deplib" + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "'$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs=$newdependency_libs + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name=$func_basename_result + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "'$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name=$func_basename_result + eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "'$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles=$newdlprefiles + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles=$newdlfiles + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles=$newdlprefiles + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test -n "$bindir"; then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result/$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that cannot go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test no,yes = "$installed,$need_relink"; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +if test link = "$opt_mode" || test relink = "$opt_mode"; then + func_mode_link ${1+"$@"} +fi + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $debug_cmd + + RM=$nonopt + files= + rmforce=false + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic=$magic + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=: ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir=$func_dirname_result + if test . = "$dir"; then + odir=$objdir + else + odir=$dir/$objdir + fi + func_basename "$file" + name=$func_basename_result + test uninstall = "$opt_mode" && odir=$dir + + # Remember odir for removal later, being careful to avoid duplicates + if test clean = "$opt_mode"; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif $rmforce; then + continue + fi + + rmfiles=$file + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case $opt_mode in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && test none != "$pic_object"; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && test none != "$non_pic_object"; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test clean = "$opt_mode"; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.$objext" + if test yes = "$fast_install" && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name"; then + func_append rmfiles " $odir/lt-$noexename.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the $objdir's in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then + func_mode_uninstall ${1+"$@"} +fi + +test -z "$opt_mode" && { + help=$generic_help + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode '$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# where we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/build-aux/missing b/build-aux/missing new file mode 100755 index 0000000..625aeb1 --- /dev/null +++ b/build-aux/missing @@ -0,0 +1,215 @@ +#! /bin/sh +# Common wrapper for a few potentially missing GNU programs. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# Originally written by Fran,cois Pinard , 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 . + +# 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 ." + 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=https://www.perl.org/ +flex_URL=https://github.com/westes/flex +gnu_software_URL=https://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 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/build-aux/test-driver b/build-aux/test-driver new file mode 100755 index 0000000..b8521a4 --- /dev/null +++ b/build-aux/test-driver @@ -0,0 +1,148 @@ +#! /bin/sh +# test-driver - basic testsuite driver script. + +scriptversion=2018-03-07.03; # UTC + +# Copyright (C) 2011-2018 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 . + +# 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 or send patches to +# . + +# 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 <$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 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/buildutil/attributes.m4 b/buildutil/attributes.m4 new file mode 100644 index 0000000..51ac88b --- /dev/null +++ b/buildutil/attributes.m4 @@ -0,0 +1,292 @@ +dnl Macros to check the presence of generic (non-typed) symbols. +dnl Copyright (c) 2006-2008 Diego Pettenò +dnl Copyright (c) 2006-2008 xine project +dnl Copyright (c) 2012 Lucas De Marchi +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +dnl 02110-1301, USA. +dnl +dnl As a special exception, the copyright owners of the +dnl macro gives unlimited permission to copy, distribute and modify the +dnl configure scripts that are the output of Autoconf when processing the +dnl Macro. You need not follow the terms of the GNU General Public +dnl License when using or distributing such scripts, even though portions +dnl of the text of the Macro appear in them. The GNU General Public +dnl License (GPL) does govern all other use of the material that +dnl constitutes the Autoconf Macro. +dnl +dnl This special exception to the GPL applies to versions of the +dnl Autoconf Macro released by this project. When you make and +dnl distribute a modified version of the Autoconf Macro, you may extend +dnl this special exception to the GPL to apply to your modified version as +dnl well. + +dnl Check if FLAG in ENV-VAR is supported by compiler and append it +dnl to WHERE-TO-APPEND variable. Note that we invert -Wno-* checks to +dnl -W* as gcc cannot test for negated warnings. If a C snippet is passed, +dnl use it, otherwise use a simple main() definition that just returns 0. +dnl CC_CHECK_FLAG_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG], [C-SNIPPET]) + +AC_DEFUN([CC_CHECK_FLAG_APPEND], [ + AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2], + AS_TR_SH([cc_cv_$2_$3]), + [eval "AS_TR_SH([cc_save_$2])='${$2}'" + eval "AS_TR_SH([$2])='${cc_save_$2} -Werror `echo "$3" | sed 's/^-Wno-/-W/'`'" + AC_LINK_IFELSE([AC_LANG_SOURCE(ifelse([$4], [], + [int main(void) { return 0; } ], + [$4]))], + [eval "AS_TR_SH([cc_cv_$2_$3])='yes'"], + [eval "AS_TR_SH([cc_cv_$2_$3])='no'"]) + eval "AS_TR_SH([$2])='$cc_save_$2'"]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_$2_$3])[ = xyes], + [eval "$1='${$1} $3'"]) +]) + +dnl CC_CHECK_FLAGS_APPEND([WHERE-TO-APPEND], [ENV-VAR], [FLAG1 FLAG2], [C-SNIPPET]) +AC_DEFUN([CC_CHECK_FLAGS_APPEND], [ + for flag in [$3]; do + CC_CHECK_FLAG_APPEND([$1], [$2], $flag, [$4]) + done +]) + +dnl Check if the flag is supported by linker (cacheable) +dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_LDFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_ldflags_$1]), + [ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LINK_IFELSE([int main() { return 1; }], + [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) + LDFLAGS="$ac_save_LDFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for +dnl the current linker to avoid undefined references in a shared object. +AC_DEFUN([CC_NOUNDEFINED], [ + dnl We check $host for which systems to enable this for. + AC_REQUIRE([AC_CANONICAL_HOST]) + + case $host in + dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads + dnl are requested, as different implementations are present; to avoid problems + dnl use -Wl,-z,defs only for those platform not behaving this way. + *-freebsd* | *-openbsd*) ;; + *) + dnl First of all check for the --no-undefined variant of GNU ld. This allows + dnl for a much more readable command line, so that people can understand what + dnl it does without going to look for what the heck -z defs does. + for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do + CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) + break + done + ;; + esac + + AC_SUBST([LDFLAGS_NOUNDEFINED]) +]) + +dnl Check for a -Werror flag or equivalent. -Werror is the GCC +dnl and ICC flag that tells the compiler to treat all the warnings +dnl as fatal. We usually need this option to make sure that some +dnl constructs (like attributes) are not simply ignored. +dnl +dnl Other compilers don't support -Werror per se, but they support +dnl an equivalent flag: +dnl - Sun Studio compiler supports -errwarn=%all +AC_DEFUN([CC_CHECK_WERROR], [ + AC_CACHE_CHECK( + [for $CC way to treat warnings as errors], + [cc_cv_werror], + [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], + [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) + ]) +]) + +AC_DEFUN([CC_CHECK_ATTRIBUTE], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], + AS_TR_SH([cc_cv_attribute_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], + [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], + [AC_DEFINE( + AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, + [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] + ) + $4], + [$5]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ + CC_CHECK_ATTRIBUTE( + [constructor],, + [void __attribute__((constructor)) ctor() { int a; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ + CC_CHECK_ATTRIBUTE( + [format], [format(printf, n, n)], + [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ + CC_CHECK_ATTRIBUTE( + [format_arg], [format_arg(printf)], + [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ + CC_CHECK_ATTRIBUTE( + [visibility_$1], [visibility("$1")], + [void __attribute__((visibility("$1"))) $1_function() { }], + [$2], [$3]) +]) + +AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ + CC_CHECK_ATTRIBUTE( + [nonnull], [nonnull()], + [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ + CC_CHECK_ATTRIBUTE( + [unused], , + [void some_function(void *foo, __attribute__((unused)) void *bar);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ + CC_CHECK_ATTRIBUTE( + [sentinel], , + [void some_function(void *foo, ...) __attribute__((sentinel));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ + CC_CHECK_ATTRIBUTE( + [deprecated], , + [void some_function(void *foo, ...) __attribute__((deprecated));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ + CC_CHECK_ATTRIBUTE( + [alias], [weak, alias], + [void other_function(void *foo) { } + void some_function(void *foo) __attribute__((weak, alias("other_function")));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ + CC_CHECK_ATTRIBUTE( + [malloc], , + [void * __attribute__((malloc)) my_alloc(int n);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_PACKED], [ + CC_CHECK_ATTRIBUTE( + [packed], , + [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONST], [ + CC_CHECK_ATTRIBUTE( + [const], , + [int __attribute__((const)) twopow(int n) { return 1 << n; } ], + [$1], [$2]) +]) + +AC_DEFUN([CC_FLAG_VISIBILITY], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], + [cc_cv_flag_visibility], + [cc_flag_visibility_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], + cc_cv_flag_visibility='yes', + cc_cv_flag_visibility='no') + CFLAGS="$cc_flag_visibility_save_CFLAGS"]) + + AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], + [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, + [Define this if the compiler supports the -fvisibility flag]) + $1], + [$2]) +]) + +AC_DEFUN([CC_FUNC_EXPECT], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if compiler has __builtin_expect function], + [cc_cv_func_expect], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [int some_function() { + int a = 3; + return (int)__builtin_expect(a, 3); + }])], + [cc_cv_func_expect=yes], + [cc_cv_func_expect=no]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([test "x$cc_cv_func_expect" = "xyes"], + [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, + [Define this if the compiler supports __builtin_expect() function]) + $1], + [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], + [cc_cv_attribute_aligned], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + for cc_attribute_align_try in 64 32 16 8 4 2; do + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ + int main() { + static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; + return c; + }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) + done + CFLAGS="$ac_save_CFLAGS" + ]) + + if test "x$cc_cv_attribute_aligned" != "x"; then + AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], + [Define the highest alignment supported]) + fi +]) diff --git a/buildutil/glib-tap.mk b/buildutil/glib-tap.mk new file mode 100644 index 0000000..9a944a0 --- /dev/null +++ b/buildutil/glib-tap.mk @@ -0,0 +1,126 @@ +# GLIB - Library of useful C routines + +AM_TESTS_ENVIRONMENT= \ + G_TEST_SRCDIR="$(abs_srcdir)" \ + G_TEST_BUILDDIR="$(abs_builddir)" \ + UNINSTALLEDTESTS=1 \ + G_DEBUG=gc-friendly \ + MALLOC_CHECK_=2 \ + MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) +LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/buildutil/tap-driver.sh +LOG_COMPILER = $(top_srcdir)/buildutil/tap-test + +TESTS = + +installed_test_LTLIBRARIES = +installed_test_PROGRAMS = +installed_test_SCRIPTS = +installed_test_DATA = +nobase_installed_test_DATA = + +noinst_SCRIPTS = +noinst_DATA = + +check_LTLIBRARIES = +check_PROGRAMS = +check_SCRIPTS = +check_DATA = + +# We support a fairly large range of possible variables. It is expected that all types of files in a test suite +# will belong in exactly one of the following variables. +# +# First, we support the usual automake suffixes, but in lowercase, with the customary meaning: +# +# test_programs, test_scripts, test_data, test_ltlibraries +# +# The above are used to list files that are involved in both uninstalled and installed testing. The +# test_programs and test_scripts are taken to be actual testcases and will be run as part of the test suite. +# Note that _data is always used with the nobase_ automake variable name to ensure that installed test data is +# installed in the same way as it appears in the package layout. +# +# In order to mark a particular file as being only for one type of testing, use 'installed' or 'uninstalled', +# like so: +# +# installed_test_programs, uninstalled_test_programs +# installed_test_scripts, uninstalled_test_scripts +# installed_test_data, uninstalled_test_data +# installed_test_ltlibraries, uninstalled_test_ltlibraries +# +# Additionally, we support 'extra' infixes for programs and scripts. This is used for support programs/scripts +# that should not themselves be run as testcases (but exist to be used from other testcases): +# +# test_extra_programs, installed_test_extra_programs, uninstalled_test_extra_programs +# test_extra_scripts, installed_test_extra_scripts, uninstalled_test_extra_scripts +# +# Additionally, for _scripts and _data, we support the customary dist_ prefix so that the named script or data +# file automatically end up in the tarball. +# +# dist_test_scripts, dist_test_data, dist_test_extra_scripts +# dist_installed_test_scripts, dist_installed_test_data, dist_installed_test_extra_scripts +# dist_uninstalled_test_scripts, dist_uninstalled_test_data, dist_uninstalled_test_extra_scripts +# +# Note that no file is automatically disted unless it appears in one of the dist_ variables. This follows the +# standard automake convention of not disting programs scripts or data by default. +# +# test_programs, test_scripts, uninstalled_test_programs and uninstalled_test_scripts (as well as their disted +# variants) will be run as part of the in-tree 'make check'. These are all assumed to be runnable under +# gtester. That's a bit strange for scripts, but it's possible. + +TESTS += $(test_programs) $(test_scripts) $(uninstalled_test_programs) $(uninstalled_test_scripts) \ + $(dist_test_scripts) $(dist_uninstalled_test_scripts) + +# Note: build even the installed-only targets during 'make check' to ensure that they still work. +# We need to do a bit of trickery here and manage disting via EXTRA_DIST instead of using dist_ prefixes to +# prevent automake from mistreating gmake functions like $(wildcard ...) and $(addprefix ...) as if they were +# filenames, including removing duplicate instances of the opening part before the space, eg. '$(addprefix'. +all_test_programs = $(test_programs) $(uninstalled_test_programs) $(installed_test_programs) \ + $(test_extra_programs) $(uninstalled_test_extra_programs) $(installed_test_extra_programs) +all_test_scripts = $(test_scripts) $(uninstalled_test_scripts) $(installed_test_scripts) \ + $(test_extra_scripts) $(uninstalled_test_extra_scripts) $(installed_test_extra_scripts) +all_dist_test_scripts = $(dist_test_scripts) $(dist_uninstalled_test_scripts) $(dist_installed_test_scripts) \ + $(dist_test_extra_scripts) $(dist_uninstalled_test_extra_scripts) $(dist_installed_test_extra_scripts) +all_test_scripts += $(all_dist_test_scripts) +EXTRA_DIST += $(all_dist_test_scripts) +all_test_data = $(test_data) $(uninstalled_test_data) $(installed_test_data) +all_dist_test_data = $(dist_test_data) $(dist_uninstalled_test_data) $(dist_installed_test_data) +all_test_data += $(all_dist_test_data) +EXTRA_DIST += $(all_dist_test_data) +all_test_ltlibs = $(test_ltlibraries) $(uninstalled_test_ltlibraries) $(installed_test_ltlibraries) + +if ENABLE_ALWAYS_BUILD_TESTS +noinst_LTLIBRARIES += $(all_test_ltlibs) +noinst_PROGRAMS += $(all_test_programs) +noinst_SCRIPTS += $(all_test_scripts) +noinst_DATA += $(all_test_data) +else +check_LTLIBRARIES += $(all_test_ltlibs) +check_PROGRAMS += $(all_test_programs) +check_SCRIPTS += $(all_test_scripts) +check_DATA += $(all_test_data) +endif + +if ENABLE_INSTALLED_TESTS +installed_test_PROGRAMS += $(test_programs) $(installed_test_programs) \ + $(test_extra_programs) $(installed_test_extra_programs) +installed_test_SCRIPTS += $(test_scripts) $(installed_test_scripts) \ + $(test_extra_scripts) $(test_installed_extra_scripts) +installed_test_SCRIPTS += $(dist_test_scripts) $(dist_test_extra_scripts) \ + $(dist_installed_test_scripts) $(dist_installed_test_extra_scripts) +installed_test_DATA += $(test_data) $(installed_test_data) +installed_test_DATA += $(dist_test_data) $(dist_installed_test_data) +installed_test_LTLIBRARIES += $(test_ltlibraries) $(installed_test_ltlibraries) +installed_testcases = $(test_programs) $(installed_test_programs) \ + $(test_scripts) $(installed_test_scripts) \ + $(dist_test_scripts) $(dist_installed_test_scripts) + +installed_test_meta_DATA = $(installed_testcases:=.test) + +%.test: %$(EXEEXT) Makefile + @$(MKDIR_P) $(dir $@) + $(AM_V_GEN) (echo '[Test]' > $@.tmp; \ + echo 'Type=session' >> $@.tmp; \ + echo 'Exec=env G_TEST_SRCDIR=$(installed_testdir) G_TEST_BUILDDIR=$(installed_testdir) $(installed_testdir)/$(notdir $<)' >> $@.tmp; \ + mv $@.tmp $@) + +CLEANFILES += $(installed_test_meta_DATA) +endif diff --git a/buildutil/glibtests.m4 b/buildutil/glibtests.m4 new file mode 100644 index 0000000..108c847 --- /dev/null +++ b/buildutil/glibtests.m4 @@ -0,0 +1,32 @@ +dnl GLIB_TESTS +dnl NOTE: this file has been modified from upstream glib; see +dnl https://github.com/ostreedev/ostree/pull/837 + +AC_DEFUN([GLIB_TESTS], +[ + AC_ARG_ENABLE(installed-tests, + AS_HELP_STRING([--enable-installed-tests], + [Enable installation of some test cases]), + [enable_installed_tests=${enableval}; + case ${enableval} in + yes) ENABLE_INSTALLED_TESTS="1" ;; + exclusive) ENABLE_INSTALLED_TESTS="1"; ENABLE_INSTALLED_TESTS_EXCLUSIVE=1 ;; + no) ENABLE_INSTALLED_TESTS="" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-installed-tests]) ;; + esac]) + AM_CONDITIONAL([ENABLE_INSTALLED_TESTS], test "$ENABLE_INSTALLED_TESTS" = "1") + AM_CONDITIONAL([ENABLE_INSTALLED_TESTS_EXCLUSIVE], test "$ENABLE_INSTALLED_TESTS_EXCLUSIVE" = "1") + AC_ARG_ENABLE(always-build-tests, + AS_HELP_STRING([--enable-always-build-tests], + [Enable always building tests during 'make all']), + [case ${enableval} in + yes) ENABLE_ALWAYS_BUILD_TESTS="1" ;; + no) ENABLE_ALWAYS_BUILD_TESTS="" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-always-build-tests]) ;; + esac]) + AM_CONDITIONAL([ENABLE_ALWAYS_BUILD_TESTS], test "$ENABLE_ALWAYS_BUILD_TESTS" = "1") + if test "$ENABLE_INSTALLED_TESTS" == "1"; then + AC_SUBST(installed_test_metadir, [${datadir}/installed-tests/]AC_PACKAGE_NAME) + AC_SUBST(installed_testdir, [${libexecdir}/installed-tests/]AC_PACKAGE_NAME) + fi +]) diff --git a/buildutil/gtk-doc.m4 b/buildutil/gtk-doc.m4 new file mode 100644 index 0000000..2d12f01 --- /dev/null +++ b/buildutil/gtk-doc.m4 @@ -0,0 +1,113 @@ +# -*- mode: autoconf -*- +# +# gtk-doc.m4 - configure macro to check for gtk-doc +# Copyright (C) 2003 James Henstridge +# 2007-2017 Stefan Sauer +# +# 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# As a special exception, the above copyright owner gives unlimited +# permission to copy, distribute and modify the configure scripts that +# are the output of Autoconf when processing the Macro. You need not +# follow the terms of the GNU General Public License when using or +# distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. + +# serial 2 + +dnl Usage: +dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) +AC_DEFUN([GTK_DOC_CHECK], +[ + AC_REQUIRE([PKG_PROG_PKG_CONFIG]) + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + + ifelse([$1],[],[gtk_doc_requires="gtk-doc"],[gtk_doc_requires="gtk-doc >= $1"]) + AC_MSG_CHECKING([for gtk-doc]) + PKG_CHECK_EXISTS([$gtk_doc_requires],[have_gtk_doc=yes],[have_gtk_doc=no]) + AC_MSG_RESULT($have_gtk_doc) + + if test "$have_gtk_doc" = "no"; then + AC_MSG_WARN([ + You will not be able to create source packages with 'make dist' + because $gtk_doc_requires is not found.]) + fi + + dnl check for tools we added during development + dnl Use AC_CHECK_PROG to avoid the check target using an absolute path that + dnl may not be writable by the user. Currently, automake requires that the + dnl test name must end in '.test'. + dnl https://bugzilla.gnome.org/show_bug.cgi?id=701638 + AC_CHECK_PROG([GTKDOC_CHECK],[gtkdoc-check],[gtkdoc-check.test]) + AC_PATH_PROG([GTKDOC_CHECK_PATH],[gtkdoc-check]) + AC_PATH_PROGS([GTKDOC_REBASE],[gtkdoc-rebase],[true]) + AC_PATH_PROG([GTKDOC_MKPDF],[gtkdoc-mkpdf]) + + dnl for overriding the documentation installation directory + AC_ARG_WITH([html-dir], + AS_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),, + [with_html_dir='${datadir}/gtk-doc/html']) + HTML_DIR="$with_html_dir" + AC_SUBST([HTML_DIR]) + + dnl enable/disable documentation building + AC_ARG_ENABLE([gtk-doc], + AS_HELP_STRING([--enable-gtk-doc], + [use gtk-doc to build documentation [[default=no]]]),, + [enable_gtk_doc=no]) + + AC_MSG_CHECKING([whether to build gtk-doc documentation]) + AC_MSG_RESULT($enable_gtk_doc) + + if test "x$enable_gtk_doc" = "xyes" && test "$have_gtk_doc" = "no"; then + AC_MSG_ERROR([ + You must have $gtk_doc_requires installed to build documentation for + $PACKAGE_NAME. Please install gtk-doc or disable building the + documentation by adding '--disable-gtk-doc' to '[$]0'.]) + fi + + dnl don't check for glib if we build glib + if test "x$PACKAGE_NAME" != "xglib"; then + dnl don't fail if someone does not have glib + PKG_CHECK_MODULES(GTKDOC_DEPS, glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0,,[:]) + fi + + dnl enable/disable output formats + AC_ARG_ENABLE([gtk-doc-html], + AS_HELP_STRING([--enable-gtk-doc-html], + [build documentation in html format [[default=yes]]]),, + [enable_gtk_doc_html=yes]) + AC_ARG_ENABLE([gtk-doc-pdf], + AS_HELP_STRING([--enable-gtk-doc-pdf], + [build documentation in pdf format [[default=no]]]),, + [enable_gtk_doc_pdf=no]) + + if test -z "$GTKDOC_MKPDF"; then + enable_gtk_doc_pdf=no + fi + + if test -z "$AM_DEFAULT_VERBOSITY"; then + AM_DEFAULT_VERBOSITY=1 + fi + AC_SUBST([AM_DEFAULT_VERBOSITY]) + + AM_CONDITIONAL([HAVE_GTK_DOC], [test x$have_gtk_doc = xyes]) + AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes]) + AM_CONDITIONAL([GTK_DOC_BUILD_HTML], [test x$enable_gtk_doc_html = xyes]) + AM_CONDITIONAL([GTK_DOC_BUILD_PDF], [test x$enable_gtk_doc_pdf = xyes]) + AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test -n "$LIBTOOL"]) + AM_CONDITIONAL([GTK_DOC_USE_REBASE], [test -n "$GTKDOC_REBASE"]) +]) diff --git a/buildutil/libglnx.m4 b/buildutil/libglnx.m4 new file mode 100644 index 0000000..5a72e98 --- /dev/null +++ b/buildutil/libglnx.m4 @@ -0,0 +1,34 @@ +AC_DEFUN([LIBGLNX_CONFIGURE], +[ +AC_CHECK_DECLS([ + renameat2, + memfd_create, + copy_file_range], + [], [], [[ +#include +#include +#include +#include +#include +#include +#include +#include +#include +]]) + +AC_ARG_ENABLE(otmpfile, + [AS_HELP_STRING([--disable-otmpfile], + [Disable use of O_TMPFILE [default=no]])],, + [enable_otmpfile=yes]) +AS_IF([test $enable_otmpfile = yes], [], [ + AC_DEFINE([DISABLE_OTMPFILE], 1, [Define if we should avoid using O_TMPFILE])]) + +AC_ARG_ENABLE(wrpseudo-compat, + [AS_HELP_STRING([--enable-wrpseudo-compat], + [Disable use of syscall() in some cases for compatibility with pseudo [default=no]])],, + [enable_wrpseudo_compat=no]) +AS_IF([test $enable_wrpseudo_compat = no], [], [ + AC_DEFINE([ENABLE_WRPSEUDO_COMPAT], 1, [Define if we should be compatible with pseudo])]) + +dnl end LIBGLNX_CONFIGURE +]) diff --git a/buildutil/libtool.m4 b/buildutil/libtool.m4 new file mode 100644 index 0000000..a644432 --- /dev/null +++ b/buildutil/libtool.m4 @@ -0,0 +1,8372 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 2014 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 . +]) + +# serial 58 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_PREPARE_CC_BASENAME +# ----------------------- +m4_defun([_LT_PREPARE_CC_BASENAME], [ +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in @S|@*""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} +])# _LT_PREPARE_CC_BASENAME + + +# _LT_CC_BASENAME(CC) +# ------------------- +# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, +# but that macro is also expanded into generated libtool script, which +# arranges for $SED and $ECHO to be set by different means. +m4_defun([_LT_CC_BASENAME], +[m4_require([_LT_PREPARE_CC_BASENAME])dnl +AC_REQUIRE([_LT_DECL_SED])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl +func_cc_basename $1 +cc_basename=$func_cc_basename_result +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl +m4_require([_LT_CMD_TRUNCATE])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from 'configure', and 'config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# 'config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain=$ac_aux_dir/ltmain.sh +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the 'libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to 'config.status' so that its +# declaration there will have the same value as in 'configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags='_LT_TAGS'dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into 'config.status', and then the shell code to quote escape them in +# for loops in 'config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# '#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test 0 = "$lt_write_fail" && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +'$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test 0 != $[#] +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try '$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try '$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test yes = "$silent" && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +_LT_COPYING +_LT_LIBTOOL_TAGS + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +_LT_PREPARE_MUNGE_PATH_LIST +_LT_PREPARE_CC_BASENAME + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS=$save_LDFLAGS + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + 10.[[012]][[,.]]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test yes = "$lt_cv_ld_force_load"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + m4_if([$1], [CXX], +[ if test yes != "$lt_cv_apple_cc_single_mod"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script that will find a shell with a builtin +# printf (that we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case $ECHO in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], + [Search for dependent libraries within DIR (or the compiler's sysroot + if not specified).])], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([$with_sysroot]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and where our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test no = "$enable_libtool_lock" || enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + emul=elf + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test yes = "[$]$2"; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS +]) + +if test yes = "[$]$2"; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring=ABCD + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n "$lt_cv_sys_max_cmd_len"; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes = "$cross_compiling"; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes != "$enable_dlopen"; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen=load_add_on + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen=LoadLibrary + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ + lt_cv_dlopen=dyld + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen=shl_load], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen=dlopen], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS=$LDFLAGS + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS=$LIBS + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test yes = "$lt_cv_dlopen_self"; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links=nottested +if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test no = "$hard_links"; then + AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", + [Define to the sub-directory where libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then + + # We can hardcode non-existent directories. + if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && + test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || + test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP"; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_PREPARE_MUNGE_PATH_LIST +# --------------------------- +# Make sure func_munge_path_list() is defined correctly. +m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], +[[# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x@S|@2 in + x) + ;; + *:) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" + ;; + x:*) + eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" + ;; + *) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + esac +} +]])# _LT_PREPARE_PATH_LIST + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary... + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" + elif test -n "$lt_multi_os_dir"; then + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS = " "; FS = "/|\n";} { + lt_foo = ""; + lt_count = 0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo = "/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +AC_ARG_VAR([LT_SYS_LIBRARY_PATH], +[User-defined run-time library search path.]) + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a[(]lib.so.V[)]' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], + [Detected run-time system search path for libraries]) +_LT_DECL([], [configure_time_lt_sys_library_path], [2], + [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program that can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$1"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac]) +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program that can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test no = "$withval" || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], +[if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi]) +rm -f conftest.i conftest2.i conftest.out]) +])# _LT_PATH_DD + + +# _LT_CMD_TRUNCATE +# ---------------- +# find command to truncate a binary pipe +m4_defun([_LT_CMD_TRUNCATE], +[m4_require([_LT_PATH_DD]) +AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], +[printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) +_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], + [Command to truncate a binary pipe]) +])# _LT_CMD_TRUNCATE + + +# _LT_CHECK_MAGIC_METHOD +# ---------------------- +# how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_MAGIC_METHOD], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +AC_CACHE_CHECK([how to recognize dependent libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# 'unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# that responds to the $file_magic_cmd with a given extended regex. +# If you have 'file' or equivalent on your system and you're not sure +# whether 'pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[[4-9]]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[[45]]*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM=$NM +else + lt_nm_to_check=${ac_tool_prefix}nm + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/$lt_tmp_nm + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the 'sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi]) +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# _LT_DLL_DEF_P([FILE]) +# --------------------- +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with func_dll_def_p in the libtool script +AC_DEFUN([_LT_DLL_DEF_P], +[dnl + test DEF = "`$SED -n dnl + -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace + -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments + -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl + -e q dnl Only consider the first "real" line + $1`" dnl +])# _LT_DLL_DEF_P + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM=-lm) + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], + [Transform the output of nm into a list of symbols to manually relocate]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([nm_interface], [lt_cv_nm_interface], [1], + [The name lister interface]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64, which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test yes = "$GCC"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ' (' and ')$', so one must not match beginning or + # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', + # as well as any symbol that contains 'd'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='$wl' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + tcc*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GCC"; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + + hpux10*) + if test yes,no = "$GCC,$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test yes,no = "$GCC,$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS=$save_LDFLAGS]) + if test yes = "$lt_cv_irix_exported_symbol"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(ld_shlibs, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + osf3*) + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. GCC discards it without '$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test yes = "$GCC"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test sequent = "$host_vendor"; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting $shlibpath_var if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC=$CC +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report what library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC=$lt_save_CC +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test no != "$CXX" && + ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || + (test g++ != "$CXX"))); then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_caught_CXX_error"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test yes = "$GXX"; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test yes = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='$wl' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GXX"; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag=$shared_flag' $wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + # The "-G" linker flag allows undefined symbols. + _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared + # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require '-G' NOT '-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + + _LT_TAGVAR(GCC, $1)=$GXX + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test yes != "$_lt_caught_CXX_error" + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case @S|@2 in + .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; + *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $prev$p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test x-L = "$p" || + test x-R = "$p"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test no = "$pre_test_object_deps_done"; then + case $prev in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)=$prev$p + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test no = "$pre_test_object_deps_done"; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)=$p + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)=$p + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test no = "$F77"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_F77"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$G77 + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_F77" + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test no = "$FC"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_FC"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_FC" + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code=$lt_simple_compile_test_code + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f "$lt_ac_sed" && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test 10 -lt "$lt_ac_count" && break + lt_ac_count=`expr $lt_ac_count + 1` + if test "$lt_ac_count" -gt "$lt_ac_max"; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine what file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/buildutil/ltoptions.m4 b/buildutil/ltoptions.m4 new file mode 100644 index 0000000..94b0829 --- /dev/null +++ b/buildutil/ltoptions.m4 @@ -0,0 +1,437 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 8 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option '$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl 'shared' nor 'disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], + [_LT_WITH_AIX_SONAME([aix])]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the 'shared' and +# 'disable-shared' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the 'static' and +# 'disable-static' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the 'fast-install' +# and 'disable-fast-install' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_AIX_SONAME([DEFAULT]) +# ---------------------------------- +# implement the --with-aix-soname flag, and support the `aix-soname=aix' +# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT +# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. +m4_define([_LT_WITH_AIX_SONAME], +[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl +shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[[5-9]]*,yes) + AC_MSG_CHECKING([which variant of shared library versioning to provide]) + AC_ARG_WITH([aix-soname], + [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], + [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], + [case $withval in + aix|svr4|both) + ;; + *) + AC_MSG_ERROR([Unknown argument to --with-aix-soname]) + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname], + [AC_CACHE_VAL([lt_cv_with_aix_soname], + [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) + with_aix_soname=$lt_cv_with_aix_soname]) + AC_MSG_RESULT([$with_aix_soname]) + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + +_LT_DECL([], [shared_archive_member_spec], [0], + [Shared archive member basename, for filename based shared library versioning on AIX])dnl +])# _LT_WITH_AIX_SONAME + +LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the 'pic-only' and 'no-pic' +# LT_INIT options. +# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [pic_mode=m4_default([$1], [default])]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/buildutil/ltsugar.m4 b/buildutil/ltsugar.m4 new file mode 100644 index 0000000..48bc934 --- /dev/null +++ b/buildutil/ltsugar.m4 @@ -0,0 +1,124 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59, which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/buildutil/ltversion.m4 b/buildutil/ltversion.m4 new file mode 100644 index 0000000..fa04b52 --- /dev/null +++ b/buildutil/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 4179 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.6]) +m4_define([LT_PACKAGE_REVISION], [2.4.6]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.6' +macro_revision='2.4.6' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/buildutil/lt~obsolete.m4 b/buildutil/lt~obsolete.m4 new file mode 100644 index 0000000..c6b26f8 --- /dev/null +++ b/buildutil/lt~obsolete.m4 @@ -0,0 +1,99 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software +# Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/buildutil/tap-driver.sh b/buildutil/tap-driver.sh new file mode 100755 index 0000000..6a52d17 --- /dev/null +++ b/buildutil/tap-driver.sh @@ -0,0 +1,654 @@ +#! /bin/sh +# Copyright (C) 2011-2013 Free Software Foundation, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 . + +# 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 or send patches to +# . + +scriptversion=2011-12-27.17; # UTC + +# Make unconditional expansion of undefined variables an error. This +# helps a lot in preventing typo-related bugs. +set -u + +me=tap-driver.sh + +fatal () +{ + echo "$me: fatal: $*" >&2 + exit 1 +} + +usage_error () +{ + echo "$me: $*" >&2 + print_usage >&2 + exit 2 +} + +print_usage () +{ + cat < + # + trap : 1 3 2 13 15 + if test $merge -gt 0; then + exec 2>&1 + else + exec 2>&3 + fi + "$@" + echo $? + ) | LC_ALL=C ${AM_TAP_AWK-awk} \ + -v me="$me" \ + -v test_script_name="$test_name" \ + -v log_file="$log_file" \ + -v trs_file="$trs_file" \ + -v expect_failure="$expect_failure" \ + -v merge="$merge" \ + -v ignore_exit="$ignore_exit" \ + -v comments="$comments" \ + -v diag_string="$diag_string" \ +' +# FIXME: the usages of "cat >&3" below could be optimized when using +# FIXME: GNU awk, and/on on systems that supports /dev/fd/. + +# Implementation note: in what follows, `result_obj` will be an +# associative array that (partly) simulates a TAP result object +# from the `TAP::Parser` perl module. + +## ----------- ## +## FUNCTIONS ## +## ----------- ## + +function fatal(msg) +{ + print me ": " msg | "cat >&2" + exit 1 +} + +function abort(where) +{ + fatal("internal error " where) +} + +# Convert a boolean to a "yes"/"no" string. +function yn(bool) +{ + return bool ? "yes" : "no"; +} + +function add_test_result(result) +{ + if (!test_results_index) + test_results_index = 0 + test_results_list[test_results_index] = result + test_results_index += 1 + test_results_seen[result] = 1; +} + +# Whether the test script should be re-run by "make recheck". +function must_recheck() +{ + for (k in test_results_seen) + if (k != "XFAIL" && k != "PASS" && k != "SKIP") + return 1 + return 0 +} + +# Whether the content of the log file associated to this test should +# be copied into the "global" test-suite.log. +function copy_in_global_log() +{ + for (k in test_results_seen) + if (k != "PASS") + return 1 + return 0 +} + +# FIXME: this can certainly be improved ... +function get_global_test_result() +{ + if ("ERROR" in test_results_seen) + return "ERROR" + if ("FAIL" in test_results_seen || "XPASS" in test_results_seen) + return "FAIL" + all_skipped = 1 + for (k in test_results_seen) + if (k != "SKIP") + all_skipped = 0 + if (all_skipped) + return "SKIP" + return "PASS"; +} + +function stringify_result_obj(result_obj) +{ + if (result_obj["is_unplanned"] || result_obj["number"] != testno) + return "ERROR" + + if (plan_seen == LATE_PLAN) + return "ERROR" + + if (result_obj["directive"] == "TODO") + return result_obj["is_ok"] ? "XPASS" : "XFAIL" + + if (result_obj["directive"] == "SKIP") + return result_obj["is_ok"] ? "SKIP" : COOKED_FAIL; + + if (length(result_obj["directive"])) + abort("in function stringify_result_obj()") + + return result_obj["is_ok"] ? COOKED_PASS : COOKED_FAIL +} + +function decorate_result(result) +{ + color_name = color_for_result[result] + if (color_name) + return color_map[color_name] "" result "" color_map["std"] + # If we are not using colorized output, or if we do not know how + # to colorize the given result, we should return it unchanged. + return result +} + +function report(result, details) +{ + if (result ~ /^(X?(PASS|FAIL)|SKIP|ERROR)/) + { + msg = ": " test_script_name + add_test_result(result) + } + else if (result == "#") + { + msg = " " test_script_name ":" + } + else + { + abort("in function report()") + } + if (length(details)) + msg = msg " " details + # Output on console might be colorized. + print decorate_result(result) msg + # Log the result in the log file too, to help debugging (this is + # especially true when said result is a TAP error or "Bail out!"). + print result msg | "cat >&3"; +} + +function testsuite_error(error_message) +{ + report("ERROR", "- " error_message) +} + +function handle_tap_result() +{ + details = result_obj["number"]; + if (length(result_obj["description"])) + details = details " " result_obj["description"] + + if (plan_seen == LATE_PLAN) + { + details = details " # AFTER LATE PLAN"; + } + else if (result_obj["is_unplanned"]) + { + details = details " # UNPLANNED"; + } + else if (result_obj["number"] != testno) + { + details = sprintf("%s # OUT-OF-ORDER (expecting %d)", + details, testno); + } + else if (result_obj["directive"]) + { + details = details " # " result_obj["directive"]; + if (length(result_obj["explanation"])) + details = details " " result_obj["explanation"] + } + + report(stringify_result_obj(result_obj), details) +} + +# `skip_reason` should be empty whenever planned > 0. +function handle_tap_plan(planned, skip_reason) +{ + planned += 0 # Avoid getting confused if, say, `planned` is "00" + if (length(skip_reason) && planned > 0) + abort("in function handle_tap_plan()") + if (plan_seen) + { + # Error, only one plan per stream is acceptable. + testsuite_error("multiple test plans") + return; + } + planned_tests = planned + # The TAP plan can come before or after *all* the TAP results; we speak + # respectively of an "early" or a "late" plan. If we see the plan line + # after at least one TAP result has been seen, assume we have a late + # plan; in this case, any further test result seen after the plan will + # be flagged as an error. + plan_seen = (testno >= 1 ? LATE_PLAN : EARLY_PLAN) + # If testno > 0, we have an error ("too many tests run") that will be + # automatically dealt with later, so do not worry about it here. If + # $plan_seen is true, we have an error due to a repeated plan, and that + # has already been dealt with above. Otherwise, we have a valid "plan + # with SKIP" specification, and should report it as a particular kind + # of SKIP result. + if (planned == 0 && testno == 0) + { + if (length(skip_reason)) + skip_reason = "- " skip_reason; + report("SKIP", skip_reason); + } +} + +function extract_tap_comment(line) +{ + if (index(line, diag_string) == 1) + { + # Strip leading `diag_string` from `line`. + line = substr(line, length(diag_string) + 1) + # And strip any leading and trailing whitespace left. + sub("^[ \t]*", "", line) + sub("[ \t]*$", "", line) + # Return what is left (if any). + return line; + } + return ""; +} + +# When this function is called, we know that line is a TAP result line, +# so that it matches the (perl) RE "^(not )?ok\b". +function setup_result_obj(line) +{ + # Get the result, and remove it from the line. + result_obj["is_ok"] = (substr(line, 1, 2) == "ok" ? 1 : 0) + sub("^(not )?ok[ \t]*", "", line) + + # If the result has an explicit number, get it and strip it; otherwise, + # automatically assing the next progresive number to it. + if (line ~ /^[0-9]+$/ || line ~ /^[0-9]+[^a-zA-Z0-9_]/) + { + match(line, "^[0-9]+") + # The final `+ 0` is to normalize numbers with leading zeros. + result_obj["number"] = substr(line, 1, RLENGTH) + 0 + line = substr(line, RLENGTH + 1) + } + else + { + result_obj["number"] = testno + } + + if (plan_seen == LATE_PLAN) + # No further test results are acceptable after a "late" TAP plan + # has been seen. + result_obj["is_unplanned"] = 1 + else if (plan_seen && testno > planned_tests) + result_obj["is_unplanned"] = 1 + else + result_obj["is_unplanned"] = 0 + + # Strip trailing and leading whitespace. + sub("^[ \t]*", "", line) + sub("[ \t]*$", "", line) + + # This will have to be corrected if we have a "TODO"/"SKIP" directive. + result_obj["description"] = line + result_obj["directive"] = "" + result_obj["explanation"] = "" + + if (index(line, "#") == 0) + return # No possible directive, nothing more to do. + + # Directives are case-insensitive. + rx = "[ \t]*#[ \t]*([tT][oO][dD][oO]|[sS][kK][iI][pP])[ \t]*" + + # See whether we have the directive, and if yes, where. + pos = match(line, rx "$") + if (!pos) + pos = match(line, rx "[^a-zA-Z0-9_]") + + # If there was no TAP directive, we have nothing more to do. + if (!pos) + return + + # Let`s now see if the TAP directive has been escaped. For example: + # escaped: ok \# SKIP + # not escaped: ok \\# SKIP + # escaped: ok \\\\\# SKIP + # not escaped: ok \ # SKIP + if (substr(line, pos, 1) == "#") + { + bslash_count = 0 + for (i = pos; i > 1 && substr(line, i - 1, 1) == "\\"; i--) + bslash_count += 1 + if (bslash_count % 2) + return # Directive was escaped. + } + + # Strip the directive and its explanation (if any) from the test + # description. + result_obj["description"] = substr(line, 1, pos - 1) + # Now remove the test description from the line, that has been dealt + # with already. + line = substr(line, pos) + # Strip the directive, and save its value (normalized to upper case). + sub("^[ \t]*#[ \t]*", "", line) + result_obj["directive"] = toupper(substr(line, 1, 4)) + line = substr(line, 5) + # Now get the explanation for the directive (if any), with leading + # and trailing whitespace removed. + sub("^[ \t]*", "", line) + sub("[ \t]*$", "", line) + result_obj["explanation"] = line +} + +function get_test_exit_message(status) +{ + if (status == 0) + return "" + if (status !~ /^[1-9][0-9]*$/) + abort("getting exit status") + if (status < 127) + exit_details = "" + else if (status == 127) + exit_details = " (command not found?)" + else if (status >= 128 && status <= 255) + exit_details = sprintf(" (terminated by signal %d?)", status - 128) + else if (status > 256 && status <= 384) + # We used to report an "abnormal termination" here, but some Korn + # shells, when a child process die due to signal number n, can leave + # in $? an exit status of 256+n instead of the more standard 128+n. + # Apparently, both behaviours are allowed by POSIX (2008), so be + # prepared to handle them both. See also Austing Group report ID + # 0000051 + exit_details = sprintf(" (terminated by signal %d?)", status - 256) + else + # Never seen in practice. + exit_details = " (abnormal termination)" + return sprintf("exited with status %d%s", status, exit_details) +} + +function write_test_results() +{ + print ":global-test-result: " get_global_test_result() > trs_file + print ":recheck: " yn(must_recheck()) > trs_file + print ":copy-in-global-log: " yn(copy_in_global_log()) > trs_file + for (i = 0; i < test_results_index; i += 1) + print ":test-result: " test_results_list[i] > trs_file + close(trs_file); +} + +BEGIN { + +## ------- ## +## SETUP ## +## ------- ## + +'"$init_colors"' + +# Properly initialized once the TAP plan is seen. +planned_tests = 0 + +COOKED_PASS = expect_failure ? "XPASS": "PASS"; +COOKED_FAIL = expect_failure ? "XFAIL": "FAIL"; + +# Enumeration-like constants to remember which kind of plan (if any) +# has been seen. It is important that NO_PLAN evaluates "false" as +# a boolean. +NO_PLAN = 0 +EARLY_PLAN = 1 +LATE_PLAN = 2 + +testno = 0 # Number of test results seen so far. +bailed_out = 0 # Whether a "Bail out!" directive has been seen. + +# Whether the TAP plan has been seen or not, and if yes, which kind +# it is ("early" is seen before any test result, "late" otherwise). +plan_seen = NO_PLAN + +## --------- ## +## PARSING ## +## --------- ## + +is_first_read = 1 + +while (1) + { + # Involutions required so that we are able to read the exit status + # from the last input line. + st = getline + if (st < 0) # I/O error. + fatal("I/O error while reading from input stream") + else if (st == 0) # End-of-input + { + if (is_first_read) + abort("in input loop: only one input line") + break + } + if (is_first_read) + { + is_first_read = 0 + nextline = $0 + continue + } + else + { + curline = nextline + nextline = $0 + $0 = curline + } + # Copy any input line verbatim into the log file. + print | "cat >&3" + # Parsing of TAP input should stop after a "Bail out!" directive. + if (bailed_out) + continue + + # TAP test result. + if ($0 ~ /^(not )?ok$/ || $0 ~ /^(not )?ok[^a-zA-Z0-9_]/) + { + testno += 1 + setup_result_obj($0) + handle_tap_result() + } + # TAP plan (normal or "SKIP" without explanation). + else if ($0 ~ /^1\.\.[0-9]+[ \t]*$/) + { + # The next two lines will put the number of planned tests in $0. + sub("^1\\.\\.", "") + sub("[^0-9]*$", "") + handle_tap_plan($0, "") + continue + } + # TAP "SKIP" plan, with an explanation. + else if ($0 ~ /^1\.\.0+[ \t]*#/) + { + # The next lines will put the skip explanation in $0, stripping + # any leading and trailing whitespace. This is a little more + # tricky in truth, since we want to also strip a potential leading + # "SKIP" string from the message. + sub("^[^#]*#[ \t]*(SKIP[: \t][ \t]*)?", "") + sub("[ \t]*$", ""); + handle_tap_plan(0, $0) + } + # "Bail out!" magic. + # Older versions of prove and TAP::Harness (e.g., 3.17) did not + # recognize a "Bail out!" directive when preceded by leading + # whitespace, but more modern versions (e.g., 3.23) do. So we + # emulate the latter, "more modern" behaviour. + else if ($0 ~ /^[ \t]*Bail out!/) + { + bailed_out = 1 + # Get the bailout message (if any), with leading and trailing + # whitespace stripped. The message remains stored in `$0`. + sub("^[ \t]*Bail out![ \t]*", ""); + sub("[ \t]*$", ""); + # Format the error message for the + bailout_message = "Bail out!" + if (length($0)) + bailout_message = bailout_message " " $0 + testsuite_error(bailout_message) + } + # Maybe we have too look for dianogtic comments too. + else if (comments != 0) + { + comment = extract_tap_comment($0); + if (length(comment)) + report("#", comment); + } + } + +## -------- ## +## FINISH ## +## -------- ## + +# A "Bail out!" directive should cause us to ignore any following TAP +# error, as well as a non-zero exit status from the TAP producer. +if (!bailed_out) + { + if (!plan_seen) + { + testsuite_error("missing test plan") + } + else if (planned_tests != testno) + { + bad_amount = testno > planned_tests ? "many" : "few" + testsuite_error(sprintf("too %s tests run (expected %d, got %d)", + bad_amount, planned_tests, testno)) + } + if (!ignore_exit) + { + # Fetch exit status from the last line. + exit_message = get_test_exit_message(nextline) + if (exit_message) + testsuite_error(exit_message) + } + } + +write_test_results() + +exit 0 + +} # End of "BEGIN" block. +' + +# TODO: document that we consume the file descriptor 3 :-( +} 3>"$log_file" + +test $? -eq 0 || fatal "I/O or internal error" + +# 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: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/buildutil/tap-test b/buildutil/tap-test new file mode 100755 index 0000000..e35f2a4 --- /dev/null +++ b/buildutil/tap-test @@ -0,0 +1,39 @@ +#! /bin/bash +# +# Run a test in tap mode, ensuring we have a temporary directory. We +# always use /var/tmp becuase we might want to use user xattrs, which +# aren't available on tmpfs. +# +# The test binary is passed as $1 + +srcd=$(cd $(dirname $1) && pwd) +bn=$(basename $1) +TEST_TMPDIR=${TEST_TMPDIR:-/var/tmp} +tempdir=$(mktemp -d $TEST_TMPDIR/tap-test.XXXXXX) +touch ${tempdir}/.testtmp +function cleanup () { + if test -f ${tempdir}/.testtmp; then + rm "${tempdir}" -rf + fi +} +function skip_cleanup() { + echo "Skipping cleanup of ${tempdir}" +} +cd ${tempdir} +timeout \ + --kill-after=60 \ + --signal=ABRT \ + $(( 600 * ${TEST_TIMEOUT_FACTOR:-1} )) \ + ${srcd}/${bn} -k --tap +rc=$? +case "${TEST_SKIP_CLEANUP:-}" in + no|"") cleanup ;; + err) + if test $rc != 0; then + skip_cleanup + else + cleanup + fi ;; + *) skip_cleanup ;; +esac +exit $rc diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..44d3a44 --- /dev/null +++ b/config.h.in @@ -0,0 +1,218 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if we are building with -fsanitize=address */ +#undef BUILDOPT_ASAN + +/* Define if we are enabling ostree trivial-httpd entrypoint */ +#undef BUILDOPT_ENABLE_TRIVIAL_HTTPD_CMDLINE + +/* Define if we enable http2 by default */ +#undef BUILDOPT_HTTP2 + +/* Define if doing a development build */ +#undef BUILDOPT_IS_DEVEL_BUILD + +/* Define if systemd and libmount */ +#undef BUILDOPT_LIBSYSTEMD_AND_LIBMOUNT + +/* Define if we are building with -fsanitize=thread */ +#undef BUILDOPT_TSAN + +/* Define if we should avoid using O_TMPFILE */ +#undef DISABLE_OTMPFILE + +/* Define if we should be compatible with pseudo */ +#undef ENABLE_WRPSEUDO_COMPAT + +/* The system grub2-mkconfig executable name */ +#undef GRUB2_MKCONFIG_PATH + +/* Define to 1 if you have the `archive_read_support_filter_all' function. */ +#undef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL + +/* Define if we have avahi-client.pc and avahi-glib.pc */ +#undef HAVE_AVAHI + +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the declaration of `copy_file_range', and to 0 if + you don't. */ +#undef HAVE_DECL_COPY_FILE_RANGE + +/* Define to 1 if you have the declaration of `memfd_create', and to 0 if you + don't. */ +#undef HAVE_DECL_MEMFD_CREATE + +/* Define to 1 if you have the declaration of `renameat2', and to 0 if you + don't. */ +#undef HAVE_DECL_RENAMEAT2 + +/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. + */ +#undef HAVE_DECL_TZNAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define if we have gnutls */ +#undef HAVE_GNUTLS + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if we have libarchive.pc */ +#undef HAVE_LIBARCHIVE + +/* Define if we have libcurl.pc */ +#undef HAVE_LIBCURL + +/* Define if we have soup or curl */ +#undef HAVE_LIBCURL_OR_LIBSOUP + +/* Define if we have libmount.pc */ +#undef HAVE_LIBMOUNT + +/* Define if using libsodium */ +#undef HAVE_LIBSODIUM + +/* Define if we have libsoup.pc */ +#undef HAVE_LIBSOUP + +/* Define if we have libsoup client certs */ +#undef HAVE_LIBSOUP_CLIENT_CERTS + +/* Define if we have libsystemd.pc */ +#undef HAVE_LIBSYSTEMD + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_FSVERITY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `mnt_unref_cache' function. */ +#undef HAVE_MNT_UNREF_CACHE + +/* Define to 1 if you have the `nanotime' function. */ +#undef HAVE_NANOTIME + +/* Define if we have openssl */ +#undef HAVE_OPENSSL + +/* Define if we have libselinux.pc */ +#undef HAVE_SELINUX + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if `tm_zone' is a member of `struct tm'. */ +#undef HAVE_STRUCT_TM_TM_ZONE + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use + `HAVE_STRUCT_TM_TM_ZONE' instead. */ +#undef HAVE_TM_ZONE + +/* Define to 1 if you don't have `tm_zone' but do have the external array + `tzname'. */ +#undef HAVE_TZNAME + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Define to disable internal GPGME support */ +#undef OSTREE_DISABLE_GPGME + +/* Define if experimental API should be enabled */ +#undef OSTREE_ENABLE_EXPERIMENTAL_API + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if your declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Define if using internal ostree-grub-generator */ +#undef USE_BUILTIN_GRUB2_MKCONFIG + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Define if we have smack.pc */ +#undef WITH_SMACK + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE diff --git a/configure b/configure new file mode 100755 index 0000000..127efaa --- /dev/null +++ b/configure @@ -0,0 +1,20822 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for libostree 2020.4. +# +# Report bugs to . +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and walters@verbum.org +$0: about your system, including any error possibly output +$0: before this message. Then install a modern shell, or +$0: manually run the script under such a shell if you do +$0: have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='libostree' +PACKAGE_TARNAME='libostree' +PACKAGE_VERSION='2020.4' +PACKAGE_STRING='libostree 2020.4' +PACKAGE_BUGREPORT='walters@verbum.org' +PACKAGE_URL='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +BUILDOPT_IS_DEVEL_BUILD_FALSE +BUILDOPT_IS_DEVEL_BUILD_TRUE +ENABLE_EXPERIMENTAL_API_FALSE +ENABLE_EXPERIMENTAL_API_TRUE +BUILDOPT_GJS_FALSE +BUILDOPT_GJS_TRUE +GJS +STATIC_COMPILER +BUILDOPT_USE_STATIC_COMPILER_FALSE +BUILDOPT_USE_STATIC_COMPILER_TRUE +GRUB2_MKCONFIG +BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE +BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE +BUILDOPT_SYSTEMD_AND_LIBMOUNT_FALSE +BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE +BUILDOPT_SYSTEMD_FALSE +BUILDOPT_SYSTEMD_TRUE +systemdsystemgeneratordir +systemdsystemunitdir +LIBSYSTEMD_LIBS +LIBSYSTEMD_CFLAGS +BUILDOPT_MKINITCPIO_FALSE +BUILDOPT_MKINITCPIO_TRUE +BUILDOPT_DRACUT_CONF_FALSE +BUILDOPT_DRACUT_CONF_TRUE +BUILDOPT_DRACUT_FALSE +BUILDOPT_DRACUT_TRUE +BUILDOPT_FUSE_FALSE +BUILDOPT_FUSE_TRUE +BUILDOPT_FUSE_LIBS +BUILDOPT_FUSE_CFLAGS +USE_LIBMOUNT_FALSE +USE_LIBMOUNT_TRUE +OT_DEP_LIBMOUNT_LIBS +OT_DEP_LIBMOUNT_CFLAGS +USE_AVAHI_FALSE +USE_AVAHI_TRUE +OT_DEP_AVAHI_LIBS +OT_DEP_AVAHI_CFLAGS +USE_GNUTLS_FALSE +USE_GNUTLS_TRUE +USE_OPENSSL_FALSE +USE_OPENSSL_TRUE +OT_DEP_CRYPTO_LIBS +OT_DEP_CRYPTO_CFLAGS +USE_SMACK_FALSE +USE_SMACK_TRUE +USE_SELINUX_FALSE +USE_SELINUX_TRUE +OT_DEP_SELINUX_LIBS +OT_DEP_SELINUX_CFLAGS +USE_LIBARCHIVE_FALSE +USE_LIBARCHIVE_TRUE +OT_DEP_LIBARCHIVE_LIBS +OT_DEP_LIBARCHIVE_CFLAGS +ENABLE_RUST_FALSE +ENABLE_RUST_TRUE +RUST_DEBUG_FALSE +RUST_DEBUG_TRUE +RUST_TARGET_SUBDIR +rustc +cargo +ENABLE_MAN_FALSE +ENABLE_MAN_TRUE +XSLTPROC +GTK_DOC_USE_REBASE_FALSE +GTK_DOC_USE_REBASE_TRUE +GTK_DOC_USE_LIBTOOL_FALSE +GTK_DOC_USE_LIBTOOL_TRUE +GTK_DOC_BUILD_PDF_FALSE +GTK_DOC_BUILD_PDF_TRUE +GTK_DOC_BUILD_HTML_FALSE +GTK_DOC_BUILD_HTML_TRUE +ENABLE_GTK_DOC_FALSE +ENABLE_GTK_DOC_TRUE +HAVE_GTK_DOC_FALSE +HAVE_GTK_DOC_TRUE +GTKDOC_DEPS_LIBS +GTKDOC_DEPS_CFLAGS +HTML_DIR +GTKDOC_MKPDF +GTKDOC_REBASE +GTKDOC_CHECK_PATH +GTKDOC_CHECK +USE_LIBSODIUM_FALSE +USE_LIBSODIUM_TRUE +OT_DEP_LIBSODIUM_LIBS +OT_DEP_LIBSODIUM_CFLAGS +USE_GPGME_FALSE +USE_GPGME_TRUE +GPG_ERROR_CONFIG +OT_DEP_GPG_ERROR_LIBS +OT_DEP_GPG_ERROR_CFLAGS +GPGME_PTHREAD_LIBS +GPGME_PTHREAD_CFLAGS +GPGME_CONFIG +OT_DEP_GPGME_LIBS +OT_DEP_GPGME_CFLAGS +BUILDOPT_INTROSPECTION_FALSE +BUILDOPT_INTROSPECTION_TRUE +HAVE_INTROSPECTION_FALSE +HAVE_INTROSPECTION_TRUE +INTROSPECTION_MAKEFILE +INTROSPECTION_LIBS +INTROSPECTION_CFLAGS +INTROSPECTION_TYPELIBDIR +INTROSPECTION_GIRDIR +INTROSPECTION_GENERATE +INTROSPECTION_COMPILER +INTROSPECTION_SCANNER +_GI_EXP_LIBDIR +_GI_EXP_DATADIR +USE_CURL_OR_SOUP_FALSE +USE_CURL_OR_SOUP_TRUE +HAVE_LIBSOUP_CLIENT_CERTS_FALSE +HAVE_LIBSOUP_CLIENT_CERTS_TRUE +USE_LIBSOUP_FALSE +USE_LIBSOUP_TRUE +OT_DEP_SOUP_LIBS +OT_DEP_SOUP_CFLAGS +USE_CURL_FALSE +USE_CURL_TRUE +OT_DEP_CURL_LIBS +OT_DEP_CURL_CFLAGS +OT_DEP_E2P_LIBS +OT_DEP_E2P_CFLAGS +OT_DEP_ZLIB_LIBS +OT_DEP_ZLIB_CFLAGS +OT_DEP_LZMA_LIBS +OT_DEP_LZMA_CFLAGS +OT_DEP_GIO_UNIX_LIBS +OT_DEP_GIO_UNIX_CFLAGS +GLIB_COMPILE_RESOURCES +GLIB_MKENUMS +GOBJECT_QUERY +GLIB_GENMARSHAL +GLIB_LIBS +GLIB_CFLAGS +BASH_COMPLETIONSDIR +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +PKG_CONFIG +installed_testdir +installed_test_metadir +ENABLE_ALWAYS_BUILD_TESTS_FALSE +ENABLE_ALWAYS_BUILD_TESTS_TRUE +ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE +ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE +ENABLE_INSTALLED_TESTS_FALSE +ENABLE_INSTALLED_TESTS_TRUE +OSTREE_FEATURES +LT_SYS_LIBRARY_PATH +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +DLLTOOL +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +SED +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +LIBTOOL +BUILDOPT_TSAN_FALSE +BUILDOPT_TSAN_TRUE +BUILDOPT_ASAN_FALSE +BUILDOPT_ASAN_TRUE +WARN_CFLAGS +RELEASE_VERSION +YEAR_VERSION +YFLAGS +YACC +EGREP +GREP +CPP +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL +am__quote' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_maintainer_mode +enable_dependency_tracking +enable_largefile +enable_static +enable_shared +with_pic +enable_fast_install +with_aix_soname +with_gnu_ld +with_sysroot +enable_libtool_lock +enable_installed_tests +enable_always_build_tests +enable_otmpfile +enable_wrpseudo_compat +enable_glibtest +with_curl +enable_http2 +with_soup +enable_libsoup_client_certs +enable_trivial_httpd_cmdline +enable_introspection +with_gpgme +with_gpgme_prefix +with_ed25519_libsodium +with_html_dir +enable_gtk_doc +enable_gtk_doc_html +enable_gtk_doc_pdf +enable_man +enable_rust +enable_rust_debug +with_libarchive +with_selinux +with_smack +with_crypto +with_openssl +with_avahi +with_libmount +enable_rofiles_fuse +with_dracut +with_mkinitcpio +with_libsystemd +with_systemdsystemunitdir +with_systemdsystemgeneratordir +with_builtin_grub2_mkconfig +with_grub2_mkconfig_path +with_static_compiler +enable_experimental_api +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +YACC +YFLAGS +LT_SYS_LIBRARY_PATH +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +BASH_COMPLETIONSDIR +GLIB_CFLAGS +GLIB_LIBS +GLIB_GENMARSHAL +GOBJECT_QUERY +GLIB_MKENUMS +GLIB_COMPILE_RESOURCES +OT_DEP_GIO_UNIX_CFLAGS +OT_DEP_GIO_UNIX_LIBS +OT_DEP_LZMA_CFLAGS +OT_DEP_LZMA_LIBS +OT_DEP_ZLIB_CFLAGS +OT_DEP_ZLIB_LIBS +OT_DEP_E2P_CFLAGS +OT_DEP_E2P_LIBS +OT_DEP_CURL_CFLAGS +OT_DEP_CURL_LIBS +OT_DEP_SOUP_CFLAGS +OT_DEP_SOUP_LIBS +OT_DEP_GPGME_CFLAGS +OT_DEP_GPGME_LIBS +OT_DEP_GPG_ERROR_CFLAGS +OT_DEP_GPG_ERROR_LIBS +OT_DEP_LIBSODIUM_CFLAGS +OT_DEP_LIBSODIUM_LIBS +GTKDOC_DEPS_CFLAGS +GTKDOC_DEPS_LIBS +OT_DEP_LIBARCHIVE_CFLAGS +OT_DEP_LIBARCHIVE_LIBS +OT_DEP_SELINUX_CFLAGS +OT_DEP_SELINUX_LIBS +OT_DEP_CRYPTO_CFLAGS +OT_DEP_CRYPTO_LIBS +OT_DEP_AVAHI_CFLAGS +OT_DEP_AVAHI_LIBS +OT_DEP_LIBMOUNT_CFLAGS +OT_DEP_LIBMOUNT_LIBS +BUILDOPT_FUSE_CFLAGS +BUILDOPT_FUSE_LIBS +LIBSYSTEMD_CFLAGS +LIBSYSTEMD_LIBS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures libostree 2020.4 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/libostree] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of libostree 2020.4:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: "make V=1") + --disable-silent-rules verbose build output (undo: "make V=0") + --disable-maintainer-mode + disable make rules and dependencies not useful (and + sometimes confusing) to the casual installer + --enable-dependency-tracking + do not reject slow dependency extractors + --disable-dependency-tracking + speeds up one-time build + --disable-largefile omit support for large files + --enable-static[=PKGS] build static libraries [default=no] + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-installed-tests + Enable installation of some test cases + --enable-always-build-tests + Enable always building tests during 'make all' + --disable-otmpfile Disable use of O_TMPFILE [default=no] + --enable-wrpseudo-compat + Disable use of syscall() in some cases for + compatibility with pseudo [default=no] + --disable-glibtest do not try to compile and run a test GLIB program + --disable-http2 Disable use of http2 (default: no) + --enable-libsoup-client-certs + Require availability of new enough libsoup TLS + client cert API (default: auto) + --enable-trivial-httpd-cmdline + Continue to support "ostree trivial-httpd" + [default=no] + --enable-introspection=[no/auto/yes] + Enable introspection for this build + --enable-gtk-doc use gtk-doc to build documentation [[default=no]] + --enable-gtk-doc-html build documentation in html format [[default=yes]] + --enable-gtk-doc-pdf build documentation in pdf format [[default=no]] + --enable-man generate man pages [default=auto] + --enable-rust Compile Rust code instead of C [default=no] + --enable-rust-debug Build Rust code with debugging information + [default=no] + --enable-rofiles-fuse generate rofiles-fuse helper [default=yes] + --enable-experimental-api + Enable unstable experimental API in libostree + [default=no] + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-aix-soname=aix|svr4|both + shared library versioning (aka "SONAME") variant to + provide on AIX, [default=aix]. + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot[=DIR] Search for dependent libraries within DIR (or the + compiler's sysroot if not specified). + --with-curl Use libcurl [default=no] + --with-soup Use libsoup [default=yes] + --with-gpgme Use gpgme [default=yes] + --with-gpgme-prefix=PFX prefix where GPGME is installed (optional) + --with-ed25519-libsodium + Use libsodium for ed25519 [default=no] + --with-html-dir=PATH path to installed docs + --without-libarchive Do not use libarchive + --without-selinux Do not use SELinux + --with-smack Enable smack + --with-crypto Choose library for checksums, one of glib, openssl, + gnutls (default: glib) + --with-openssl Enable use of OpenSSL libcrypto (checksums) + --without-avahi Do not use Avahi + --without-libmount Do not use libmount + --with-dracut Install dracut module (default: no) + --with-mkinitcpio Install mkinitcpio module (default: no) + --without-libsystemd Do not use libsystemd + --with-systemdsystemunitdir=DIR + Directory for systemd service files + --with-systemdsystemgeneratordir=DIR + Directory for systemd generators + --with-builtin-grub2-mkconfig + Use a builtin minimal grub2-mkconfig to generate a + GRUB2 configuration file (default: no) + --with-grub2-mkconfig-path + Path to grub2-mkconfig + --with-static-compiler Use the given compiler to build ostree-prepare-root + statically linked (default: no) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + YACC The `Yet Another Compiler Compiler' implementation to use. + Defaults to the first program found out of: `bison -y', `byacc', + `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + LT_SYS_LIBRARY_PATH + User-defined run-time library search path. + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + BASH_COMPLETIONSDIR + value of completionsdir for bash-completion, overriding + pkg-config + GLIB_CFLAGS C compiler flags for GLIB, overriding pkg-config + GLIB_LIBS linker flags for GLIB, overriding pkg-config + GLIB_GENMARSHAL + value of glib_genmarshal for glib-2.0, overriding pkg-config + GOBJECT_QUERY + value of gobject_query for glib-2.0, overriding pkg-config + GLIB_MKENUMS + value of glib_mkenums for glib-2.0, overriding pkg-config + GLIB_COMPILE_RESOURCES + value of glib_compile_resources for gio-2.0, overriding + pkg-config + OT_DEP_GIO_UNIX_CFLAGS + C compiler flags for OT_DEP_GIO_UNIX, overriding pkg-config + OT_DEP_GIO_UNIX_LIBS + linker flags for OT_DEP_GIO_UNIX, overriding pkg-config + OT_DEP_LZMA_CFLAGS + C compiler flags for OT_DEP_LZMA, overriding pkg-config + OT_DEP_LZMA_LIBS + linker flags for OT_DEP_LZMA, overriding pkg-config + OT_DEP_ZLIB_CFLAGS + C compiler flags for OT_DEP_ZLIB, overriding pkg-config + OT_DEP_ZLIB_LIBS + linker flags for OT_DEP_ZLIB, overriding pkg-config + OT_DEP_E2P_CFLAGS + C compiler flags for OT_DEP_E2P, overriding pkg-config + OT_DEP_E2P_LIBS + linker flags for OT_DEP_E2P, overriding pkg-config + OT_DEP_CURL_CFLAGS + C compiler flags for OT_DEP_CURL, overriding pkg-config + OT_DEP_CURL_LIBS + linker flags for OT_DEP_CURL, overriding pkg-config + OT_DEP_SOUP_CFLAGS + C compiler flags for OT_DEP_SOUP, overriding pkg-config + OT_DEP_SOUP_LIBS + linker flags for OT_DEP_SOUP, overriding pkg-config + OT_DEP_GPGME_CFLAGS + C compiler flags for OT_DEP_GPGME, overriding pkg-config + OT_DEP_GPGME_LIBS + linker flags for OT_DEP_GPGME, overriding pkg-config + OT_DEP_GPG_ERROR_CFLAGS + C compiler flags for OT_DEP_GPG_ERROR, overriding pkg-config + OT_DEP_GPG_ERROR_LIBS + linker flags for OT_DEP_GPG_ERROR, overriding pkg-config + OT_DEP_LIBSODIUM_CFLAGS + C compiler flags for OT_DEP_LIBSODIUM, overriding pkg-config + OT_DEP_LIBSODIUM_LIBS + linker flags for OT_DEP_LIBSODIUM, overriding pkg-config + GTKDOC_DEPS_CFLAGS + C compiler flags for GTKDOC_DEPS, overriding pkg-config + GTKDOC_DEPS_LIBS + linker flags for GTKDOC_DEPS, overriding pkg-config + OT_DEP_LIBARCHIVE_CFLAGS + C compiler flags for OT_DEP_LIBARCHIVE, overriding pkg-config + OT_DEP_LIBARCHIVE_LIBS + linker flags for OT_DEP_LIBARCHIVE, overriding pkg-config + OT_DEP_SELINUX_CFLAGS + C compiler flags for OT_DEP_SELINUX, overriding pkg-config + OT_DEP_SELINUX_LIBS + linker flags for OT_DEP_SELINUX, overriding pkg-config + OT_DEP_CRYPTO_CFLAGS + C compiler flags for OT_DEP_CRYPTO, overriding pkg-config + OT_DEP_CRYPTO_LIBS + linker flags for OT_DEP_CRYPTO, overriding pkg-config + OT_DEP_AVAHI_CFLAGS + C compiler flags for OT_DEP_AVAHI, overriding pkg-config + OT_DEP_AVAHI_LIBS + linker flags for OT_DEP_AVAHI, overriding pkg-config + OT_DEP_LIBMOUNT_CFLAGS + C compiler flags for OT_DEP_LIBMOUNT, overriding pkg-config + OT_DEP_LIBMOUNT_LIBS + linker flags for OT_DEP_LIBMOUNT, overriding pkg-config + BUILDOPT_FUSE_CFLAGS + C compiler flags for BUILDOPT_FUSE, overriding pkg-config + BUILDOPT_FUSE_LIBS + linker flags for BUILDOPT_FUSE, overriding pkg-config + LIBSYSTEMD_CFLAGS + C compiler flags for LIBSYSTEMD, overriding pkg-config + LIBSYSTEMD_LIBS + linker flags for LIBSYSTEMD, overriding pkg-config + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +libostree configure 2020.4 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## --------------------------------- ## +## Report this to walters@verbum.org ## +## --------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl + +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$5 +int +main () +{ +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else + eval "$4=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$4 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_member +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by libostree $as_me 2020.4, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +is_release_build=yes +ac_config_headers="$ac_config_headers config.h" + + +ac_aux_dir= +for ac_dir in build-aux "$srcdir"/build-aux; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in build-aux \"$srcdir\"/build-aux" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + +am__api_version='1.16' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken + alias in your environment" "$LINENO" 5 + fi + if test "$2" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi + +rm -f conftest.file + +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='libostree' + VERSION='2020.4' + + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +mkdir_p='$(MKDIR_P)' + +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar plaintar pax cpio none' + +# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5 +$as_echo_n "checking whether UID '$am_uid' is supported by ustar format... " >&6; } + if test $am_uid -le $am_max_uid; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5 +$as_echo_n "checking whether GID '$am_gid' is supported by ustar format... " >&6; } + if test $am_gid -le $am_max_gid; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + _am_tools=none + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5 +$as_echo_n "checking how to create a ustar tar archive... " >&6; } + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_ustar-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + { echo "$as_me:$LINENO: $_am_tar --version" >&5 + ($_am_tar --version) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && break + done + am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x ustar -w "$$tardir"' + am__tar_='pax -L -x ustar -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H ustar -L' + am__tar_='find "$tardir" -print | cpio -o -H ustar -L' + am__untar='cpio -i -H ustar -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_ustar}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 + (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + rm -rf conftest.dir + if test -s conftest.tar; then + { echo "$as_me:$LINENO: $am__untar &5 + ($am__untar &5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + { echo "$as_me:$LINENO: cat conftest.dir/file" >&5 + (cat conftest.dir/file) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + if ${am_cv_prog_tar_ustar+:} false; then : + $as_echo_n "(cached) " >&6 +else + am_cv_prog_tar_ustar=$_am_tool +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5 +$as_echo "$am_cv_prog_tar_ustar" >&6; } + + + + + + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 + fi +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in # ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=0;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 +$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } +cat > confinc.mk << 'END' +am__doit: + @echo this is the am__doit target >confinc.out +.PHONY: am__doit +END +am__include="#" +am__quote= +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 + (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + case $?:`cat confinc.out 2>/dev/null` in #( + '0:this is the am__doit target') : + case $s in #( + BSD) : + am__include='.include' am__quote='"' ;; #( + *) : + am__include='include' am__quote='' ;; +esac ;; #( + *) : + ;; +esac + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 +$as_echo "${_am_result}" >&6; } + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" +if test "x$ac_cv_header_minix_config_h" = xyes; then : + MINIX=yes +else + MINIX= +fi + + + if test "$MINIX" = yes; then + +$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h + + +$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h + + +$as_echo "#define _MINIX 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 +$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if ${ac_cv_safe_to_define___extensions__+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# define __EXTENSIONS__ 1 + $ac_includes_default +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_safe_to_define___extensions__=yes +else + ac_cv_safe_to_define___extensions__=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } + test $ac_cv_safe_to_define___extensions__ = yes && + $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h + + $as_echo "#define _ALL_SOURCE 1" >>confdefs.h + + $as_echo "#define _GNU_SOURCE 1" >>confdefs.h + + $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h + + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 +$as_echo_n "checking for special C compiler options needed for large files... " >&6; } +if ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + if ac_fn_c_try_compile "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_largefile_CC=' -n32'; break +fi +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +$as_echo "$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } +if ${ac_cv_sys_file_offset_bits+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_file_offset_bits=64; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +$as_echo "$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -rf conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 +$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } +if ${ac_cv_sys_large_files+:} false; then : + $as_echo_n "(cached) " >&6 +else + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=no; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_sys_large_files=1; break +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +$as_echo "$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -rf conftest* + fi + + +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } +if ${am_cv_prog_cc_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 + ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +$as_echo "$am_cv_prog_cc_c_o" >&6; } +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_YACC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_YACC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +$as_echo "$YACC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + + +YEAR_VERSION=2020 + +RELEASE_VERSION=4 + +PACKAGE_VERSION=2020.4 + + +if echo "$CFLAGS" | grep -q -E -e '-Werror($| )'; then : + +else + + + for flag in \ + -pipe \ + -Wall \ + -Werror=empty-body \ + -Werror=strict-prototypes \ + -Werror=missing-prototypes \ + -Werror=implicit-function-declaration \ + "-Werror=format=2 -Werror=format-security -Werror=format-nonliteral" \ + -Werror=pointer-arith -Werror=init-self \ + -Werror=missing-declarations \ + -Werror=return-type \ + -Werror=switch \ + -Werror=overflow \ + -Werror=int-conversion \ + -Werror=parentheses \ + -Werror=undef \ + -Werror=incompatible-pointer-types \ + -Werror=misleading-indentation \ + -Werror=missing-include-dirs -Werror=aggregate-return \ + -Wstrict-aliasing=2 \ + -Werror=unused-result \ +; do + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports flag $flag in envvar CFLAGS" >&5 +$as_echo_n "checking if $CC supports flag $flag in envvar CFLAGS... " >&6; } +if { as_var=`$as_echo "cc_cv_CFLAGS_$flag" | $as_tr_sh`; eval \${$as_var+:} false; }; then : + $as_echo_n "(cached) " >&6 +else + eval "cc_save_CFLAGS='${CFLAGS}'" + eval "CFLAGS='${cc_save_CFLAGS} -Werror `echo "$flag" | sed 's/^-Wno-/-W/'`'" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "`$as_echo "cc_cv_CFLAGS_$flag" | $as_tr_sh`='yes'" +else + eval "`$as_echo "cc_cv_CFLAGS_$flag" | $as_tr_sh`='no'" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + eval "CFLAGS='$cc_save_CFLAGS'" +fi +eval ac_res=\$`$as_echo "cc_cv_CFLAGS_$flag" | $as_tr_sh` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + + if eval test x$`$as_echo "cc_cv_CFLAGS_$flag" | $as_tr_sh` = xyes; then : + eval "WARN_CFLAGS='${WARN_CFLAGS} $flag'" +fi + + done + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=address in CFLAGS" >&5 +$as_echo_n "checking for -fsanitize=address in CFLAGS... " >&6; } +if echo $CFLAGS | grep -q -e -fsanitize=address; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + using_asan=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + if test x$using_asan = xyes; then + BUILDOPT_ASAN_TRUE= + BUILDOPT_ASAN_FALSE='#' +else + BUILDOPT_ASAN_TRUE='#' + BUILDOPT_ASAN_FALSE= +fi + +if test -z "$BUILDOPT_ASAN_TRUE"; then : + +$as_echo "#define BUILDOPT_ASAN 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=thread in CFLAGS" >&5 +$as_echo_n "checking for -fsanitize=thread in CFLAGS... " >&6; } +if echo $CFLAGS | grep -q -e -fsanitize=thread; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + using_tsan=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + if test x$using_tsan = xyes; then + BUILDOPT_TSAN_TRUE= + BUILDOPT_TSAN_FALSE='#' +else + BUILDOPT_TSAN_TRUE='#' + BUILDOPT_TSAN_FALSE= +fi + +if test -z "$BUILDOPT_TSAN_TRUE"; then : + +$as_echo "#define BUILDOPT_TSAN 1" >>confdefs.h + +fi + +# Initialize libtool + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.6' +macro_revision='2.4.6' + + + + + + + + + + + + + +ltmain=$ac_aux_dir/ltmain.sh + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case $ECHO in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM=$NM +else + lt_nm_to_check=${ac_tool_prefix}nm + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/$lt_tmp_nm + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the 'sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring=ABCD + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n "$lt_cv_sys_max_cmd_len"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test yes != "$GCC"; then + reload_cmds=false + fi + ;; + darwin*) + if test yes = "$GCC"; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# 'unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# that responds to the $file_magic_cmd with a given extended regex. +# If you have 'file' or equivalent on your system and you're not sure +# whether 'pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 +$as_echo "$with_sysroot" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 +$as_echo_n "checking for a working dd... " >&6; } +if ${ac_cv_path_lt_DD+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +if test -z "$lt_DD"; then + ac_path_lt_DD_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in dd; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_lt_DD" || continue +if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi + $ac_path_lt_DD_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_lt_DD"; then + : + fi +else + ac_cv_path_lt_DD=$lt_DD +fi + +rm -f conftest.i conftest2.i conftest.out +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 +$as_echo "$ac_cv_path_lt_DD" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 +$as_echo_n "checking how to truncate binary pipes... " >&6; } +if ${lt_cv_truncate_bin+:} false; then : + $as_echo_n "(cached) " >&6 +else + printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 +$as_echo "$lt_cv_truncate_bin" >&6; } + + + + + + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test no = "$enable_libtool_lock" || enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + emul=elf + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + 10.[012][,.]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + + +# Set options +# Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + enable_static=no +fi + + + + + + + + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + pic_mode=default +fi + + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS=$lt_save_ifs + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[5-9]*,yes) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 +$as_echo_n "checking which variant of shared library versioning to provide... " >&6; } + +# Check whether --with-aix-soname was given. +if test "${with_aix_soname+set}" = set; then : + withval=$with_aix_soname; case $withval in + aix|svr4|both) + ;; + *) + as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname +else + if ${lt_cv_with_aix_soname+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_with_aix_soname=aix +fi + + with_aix_soname=$lt_cv_with_aix_soname +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 +$as_echo "$with_aix_soname" >&6; } + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +func_cc_basename $compiler +cc_basename=$func_cc_basename_result + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/${ac_tool_prefix}file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/file"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac +fi + +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC=$CC +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test yes = "$GCC"; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + case $host_os in + os2*) + lt_prog_compiler_static='$wl-static' + ;; + esac + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='$wl-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_pic_works"; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test yes = "$lt_cv_prog_compiler_static_works"; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links=nottested +if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test no = "$hard_links"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ' (' and ')$', so one must not match beginning or + # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', + # as well as any symbol that contains 'd'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='$wl' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + export_dynamic_flag_spec='$wl--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='$wl--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + tcc*) + export_dynamic_flag_spec='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test no = "$ld_shlibs"; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + hardcode_direct=no + hardcode_direct_absolute=no + ;; + esac + + if test yes = "$GCC"; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + export_dynamic_flag_spec='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=/usr/lib:/lib + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' $wl-bernotok' + allow_undefined_flag=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test yes = "$lt_cv_ld_force_load"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test yes = "$GCC"; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='$wl-E' + ;; + + hpux10*) + if test yes,no = "$GCC,$with_gnu_ld"; then + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='$wl-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test yes,no = "$GCC,$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test yes = "$lt_cv_prog_compiler__b"; then + archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test no = "$with_gnu_ld"; then + hardcode_libdir_flag_spec='$wl+b $wl$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='$wl-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test yes = "$GCC"; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test yes = "$lt_cv_irix_exported_symbol"; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + ld_shlibs=yes + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + export_dynamic_flag_spec='$wl-E' + else + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='$wl-rpath,$libdir' + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + shrext_cmds=.dll + archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + enable_shared_with_static_runtimes=yes + ;; + + osf3*) + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + allow_undefined_flag=' $wl-expect_unresolved $wl\*' + archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='$wl' + archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. GCC discards it without '$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test yes = "$GCC"; then + whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test sequent = "$host_vendor"; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='$wl-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='$wl-z,text' + allow_undefined_flag='$wl-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='$wl-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='$wl-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test no = "$ld_shlibs" && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary... + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" + elif test -n "$lt_multi_os_dir"; then + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS = " "; FS = "/|\n";} { + lt_foo = ""; + lt_count = 0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo = "/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([A-Za-z]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + + + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a(lib.so.V)' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + hardcode_libdir_flag_spec='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test yes = "$hardcode_automatic"; then + + # We can hardcode non-existent directories. + if test no != "$hardcode_direct" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && + test no != "$hardcode_minus_L"; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test relink = "$hardcode_action" || + test yes = "$inherit_rpath"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test yes != "$enable_dlopen"; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen=load_add_on + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen=LoadLibrary + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else + + lt_cv_dlopen=dyld + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen=shl_load +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen=dlopen +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS=$LDFLAGS + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS=$LIBS + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test yes = "$cross_compiling"; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test yes = "$lt_cv_dlopen_self"; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test yes = "$cross_compiling"; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP"; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report what library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + +OSTREE_FEATURES="" + + + + # Check whether --enable-installed-tests was given. +if test "${enable_installed_tests+set}" = set; then : + enableval=$enable_installed_tests; enable_installed_tests=${enableval}; + case ${enableval} in + yes) ENABLE_INSTALLED_TESTS="1" ;; + exclusive) ENABLE_INSTALLED_TESTS="1"; ENABLE_INSTALLED_TESTS_EXCLUSIVE=1 ;; + no) ENABLE_INSTALLED_TESTS="" ;; + *) as_fn_error $? "bad value ${enableval} for --enable-installed-tests" "$LINENO" 5 ;; + esac +fi + + if test "$ENABLE_INSTALLED_TESTS" = "1"; then + ENABLE_INSTALLED_TESTS_TRUE= + ENABLE_INSTALLED_TESTS_FALSE='#' +else + ENABLE_INSTALLED_TESTS_TRUE='#' + ENABLE_INSTALLED_TESTS_FALSE= +fi + + if test "$ENABLE_INSTALLED_TESTS_EXCLUSIVE" = "1"; then + ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE= + ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE='#' +else + ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE='#' + ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE= +fi + + # Check whether --enable-always-build-tests was given. +if test "${enable_always_build_tests+set}" = set; then : + enableval=$enable_always_build_tests; case ${enableval} in + yes) ENABLE_ALWAYS_BUILD_TESTS="1" ;; + no) ENABLE_ALWAYS_BUILD_TESTS="" ;; + *) as_fn_error $? "bad value ${enableval} for --enable-always-build-tests" "$LINENO" 5 ;; + esac +fi + + if test "$ENABLE_ALWAYS_BUILD_TESTS" = "1"; then + ENABLE_ALWAYS_BUILD_TESTS_TRUE= + ENABLE_ALWAYS_BUILD_TESTS_FALSE='#' +else + ENABLE_ALWAYS_BUILD_TESTS_TRUE='#' + ENABLE_ALWAYS_BUILD_TESTS_FALSE= +fi + + if test "$ENABLE_INSTALLED_TESTS" == "1"; then + installed_test_metadir=${datadir}/installed-tests/libostree + + installed_testdir=${libexecdir}/installed-tests/libostree + + fi + + +ac_fn_c_check_decl "$LINENO" "renameat2" "ac_cv_have_decl_renameat2" " +#include +#include +#include +#include +#include +#include +#include +#include +#include + +" +if test "x$ac_cv_have_decl_renameat2" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_RENAMEAT2 $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "memfd_create" "ac_cv_have_decl_memfd_create" " +#include +#include +#include +#include +#include +#include +#include +#include +#include + +" +if test "x$ac_cv_have_decl_memfd_create" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_MEMFD_CREATE $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "copy_file_range" "ac_cv_have_decl_copy_file_range" " +#include +#include +#include +#include +#include +#include +#include +#include +#include + +" +if test "x$ac_cv_have_decl_copy_file_range" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_COPY_FILE_RANGE $ac_have_decl +_ACEOF + + +# Check whether --enable-otmpfile was given. +if test "${enable_otmpfile+set}" = set; then : + enableval=$enable_otmpfile; +else + enable_otmpfile=yes +fi + +if test $enable_otmpfile = yes; then : + +else + + +$as_echo "#define DISABLE_OTMPFILE 1" >>confdefs.h + +fi + +# Check whether --enable-wrpseudo-compat was given. +if test "${enable_wrpseudo_compat+set}" = set; then : + enableval=$enable_wrpseudo_compat; +else + enable_wrpseudo_compat=no +fi + +if test $enable_wrpseudo_compat = no; then : + +else + + +$as_echo "#define ENABLE_WRPSEUDO_COMPAT 1" >>confdefs.h + +fi + + + +for ac_func in nanotime clock_gettime +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 +$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } +if ${ac_cv_struct_tm+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm tm; + int *p = &tm.tm_sec; + return !p; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_struct_tm=time.h +else + ac_cv_struct_tm=sys/time.h +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 +$as_echo "$ac_cv_struct_tm" >&6; } +if test $ac_cv_struct_tm = sys/time.h; then + +$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h + +fi + +ac_fn_c_check_member "$LINENO" "struct tm" "tm_zone" "ac_cv_member_struct_tm_tm_zone" "#include +#include <$ac_cv_struct_tm> + +" +if test "x$ac_cv_member_struct_tm_tm_zone" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_TM_TM_ZONE 1 +_ACEOF + + +fi + +if test "$ac_cv_member_struct_tm_tm_zone" = yes; then + +$as_echo "#define HAVE_TM_ZONE 1" >>confdefs.h + +else + ac_fn_c_check_decl "$LINENO" "tzname" "ac_cv_have_decl_tzname" "#include +" +if test "x$ac_cv_have_decl_tzname" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_TZNAME $ac_have_decl +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tzname" >&5 +$as_echo_n "checking for tzname... " >&6; } +if ${ac_cv_var_tzname+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#if !HAVE_DECL_TZNAME +extern char *tzname[]; +#endif + +int +main () +{ +return tzname[0][0]; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_var_tzname=yes +else + ac_cv_var_tzname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_var_tzname" >&5 +$as_echo "$ac_cv_var_tzname" >&6; } + if test $ac_cv_var_tzname = yes; then + +$as_echo "#define HAVE_TZNAME 1" >>confdefs.h + + fi +fi + +ac_fn_c_check_header_mongrel "$LINENO" "sys/xattr.h" "ac_cv_header_sys_xattr_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_xattr_h" = xyes; then : + +else + as_fn_error $? "You must have sys/xattr.h from glibc" "$LINENO" 5 +fi + + + +if test "$YACC" != "bison -y"; then : + as_fn_error $? "bison not found but required" "$LINENO" 5 +fi + + + + + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +$as_echo "$ac_pt_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + PKG_CONFIG="" + fi +fi + +# PKG_CHECK_VAR added to pkg-config 0.28 + + + +if test -n "$BASH_COMPLETIONSDIR"; then + pkg_cv_BASH_COMPLETIONSDIR="$BASH_COMPLETIONSDIR" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bash-completion\""; } >&5 + ($PKG_CONFIG --exists --print-errors "bash-completion") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_BASH_COMPLETIONSDIR=`$PKG_CONFIG --variable="completionsdir" "bash-completion" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +BASH_COMPLETIONSDIR=$pkg_cv_BASH_COMPLETIONSDIR + +if test "x$BASH_COMPLETIONSDIR" = x""; then : + BASH_COMPLETIONSDIR="${datadir}/bash-completion/completions" +fi + + + + + +# Check whether --enable-glibtest was given. +if test "${enable_glibtest+set}" = set; then : + enableval=$enable_glibtest; +else + enable_glibtest=yes +fi + + + min_glib_version=2.0.0 + pkg_config_args="glib-2.0 >= $min_glib_version" + for module in . + do + case "$module" in + gmodule) + pkg_config_args="$pkg_config_args gmodule-2.0" + ;; + gmodule-no-export) + pkg_config_args="$pkg_config_args gmodule-no-export-2.0" + ;; + gobject) + pkg_config_args="$pkg_config_args gobject-2.0" + ;; + gthread) + pkg_config_args="$pkg_config_args gthread-2.0" + ;; + gio*) + pkg_config_args="$pkg_config_args $module-2.0" + ;; + esac + done + + + + + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +$as_echo "$ac_pt_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.16 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + PKG_CONFIG="" + fi +fi + + no_glib="" + + if test "x$PKG_CONFIG" = x ; then + no_glib=yes + PKG_CONFIG=no + fi + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIB" >&5 +$as_echo_n "checking for GLIB... " >&6; } + +if test -n "$GLIB_CFLAGS"; then + pkg_cv_GLIB_CFLAGS="$GLIB_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$pkg_config_args\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$pkg_config_args") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GLIB_CFLAGS=`$PKG_CONFIG --cflags "$pkg_config_args" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GLIB_LIBS"; then + pkg_cv_GLIB_LIBS="$GLIB_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$pkg_config_args\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$pkg_config_args") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GLIB_LIBS=`$PKG_CONFIG --libs "$pkg_config_args" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$pkg_config_args" 2>&1` + else + GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$pkg_config_args" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GLIB_PKG_ERRORS" >&5 + + : +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + : +else + GLIB_CFLAGS=$pkg_cv_GLIB_CFLAGS + GLIB_LIBS=$pkg_cv_GLIB_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + : +fi + + +if test -n "$GLIB_GENMARSHAL"; then + pkg_cv_GLIB_GENMARSHAL="$GLIB_GENMARSHAL" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "glib-2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GLIB_GENMARSHAL=`$PKG_CONFIG --variable="glib_genmarshal" "glib-2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +GLIB_GENMARSHAL=$pkg_cv_GLIB_GENMARSHAL + +if test "x$GLIB_GENMARSHAL" = x""; then : + +fi + +if test -n "$GOBJECT_QUERY"; then + pkg_cv_GOBJECT_QUERY="$GOBJECT_QUERY" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "glib-2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GOBJECT_QUERY=`$PKG_CONFIG --variable="gobject_query" "glib-2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +GOBJECT_QUERY=$pkg_cv_GOBJECT_QUERY + +if test "x$GOBJECT_QUERY" = x""; then : + +fi + +if test -n "$GLIB_MKENUMS"; then + pkg_cv_GLIB_MKENUMS="$GLIB_MKENUMS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "glib-2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GLIB_MKENUMS=`$PKG_CONFIG --variable="glib_mkenums" "glib-2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +GLIB_MKENUMS=$pkg_cv_GLIB_MKENUMS + +if test "x$GLIB_MKENUMS" = x""; then : + +fi + +if test -n "$GLIB_COMPILE_RESOURCES"; then + pkg_cv_GLIB_COMPILE_RESOURCES="$GLIB_COMPILE_RESOURCES" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gio-2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gio-2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable="glib_compile_resources" "gio-2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +GLIB_COMPILE_RESOURCES=$pkg_cv_GLIB_COMPILE_RESOURCES + +if test "x$GLIB_COMPILE_RESOURCES" = x""; then : + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIB - version >= $min_glib_version" >&5 +$as_echo_n "checking for GLIB - version >= $min_glib_version... " >&6; } + + if test x$PKG_CONFIG != xno ; then + ## don't try to run the test against uninstalled libtool libs + if $PKG_CONFIG --uninstalled $pkg_config_args; then + echo "Will use uninstalled version of GLib found in PKG_CONFIG_PATH" + enable_glibtest=no + fi + + if $PKG_CONFIG --atleast-version $min_glib_version $pkg_config_args; then + : + else + no_glib=yes + fi + fi + + if test x"$no_glib" = x ; then + glib_config_major_version=`$PKG_CONFIG --modversion glib-2.0 | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` + glib_config_minor_version=`$PKG_CONFIG --modversion glib-2.0 | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` + glib_config_micro_version=`$PKG_CONFIG --modversion glib-2.0 | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` + if test "x$enable_glibtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$GLIB_LIBS $LIBS" + rm -f conf.glibtest + if test "$cross_compiling" = yes; then : + echo $ac_n "cross compiling; assumed OK... $ac_c" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include + +int +main (void) +{ + unsigned int major, minor, micro; + + fclose (fopen ("conf.glibtest", "w")); + + if (sscanf("$min_glib_version", "%u.%u.%u", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_glib_version"); + exit(1); + } + + if ((glib_major_version != $glib_config_major_version) || + (glib_minor_version != $glib_config_minor_version) || + (glib_micro_version != $glib_config_micro_version)) + { + printf("\n*** 'pkg-config --modversion glib-2.0' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", + $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, + glib_major_version, glib_minor_version, glib_micro_version); + printf ("*** was found! If pkg-config was correct, then it is best\n"); + printf ("*** to remove the old version of GLib. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); + printf("*** to point to the correct configuration files\n"); + } + else if ((glib_major_version != GLIB_MAJOR_VERSION) || + (glib_minor_version != GLIB_MINOR_VERSION) || + (glib_micro_version != GLIB_MICRO_VERSION)) + { + printf("*** GLIB header files (version %d.%d.%d) do not match\n", + GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); + printf("*** library (version %d.%d.%d)\n", + glib_major_version, glib_minor_version, glib_micro_version); + } + else + { + if ((glib_major_version > major) || + ((glib_major_version == major) && (glib_minor_version > minor)) || + ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GLIB (%u.%u.%u) was found.\n", + glib_major_version, glib_minor_version, glib_micro_version); + printf("*** You need a version of GLIB newer than %u.%u.%u. The latest version of\n", + major, minor, micro); + printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GLIB, but you can also set the PKG_CONFIG environment to point to the\n"); + printf("*** correct copy of pkg-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + no_glib=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_glib" = x ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)" >&5 +$as_echo "yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)" >&6; } + : + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + if test "$PKG_CONFIG" = "no" ; then + echo "*** A new enough version of pkg-config was not found." + echo "*** See http://www.freedesktop.org/software/pkgconfig/" + else + if test -f conf.glibtest ; then + : + else + echo "*** Could not run GLIB test program, checking why..." + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$LIBS $GLIB_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GLIB or finding the wrong" + echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" +else + echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GLIB is incorrectly installed." +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GLIB_CFLAGS="" + GLIB_LIBS="" + GLIB_GENMARSHAL="" + GOBJECT_QUERY="" + GLIB_MKENUMS="" + GLIB_COMPILE_RESOURCES="" + as_fn_error $? "GLib not found" "$LINENO" 5 + fi + rm -f conf.glibtest + + +GIO_DEPENDENCY="gio-unix-2.0 >= 2.40.0" + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_GIO_UNIX" >&5 +$as_echo_n "checking for OT_DEP_GIO_UNIX... " >&6; } + +if test -n "$OT_DEP_GIO_UNIX_CFLAGS"; then + pkg_cv_OT_DEP_GIO_UNIX_CFLAGS="$OT_DEP_GIO_UNIX_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$GIO_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$GIO_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_GIO_UNIX_CFLAGS=`$PKG_CONFIG --cflags "$GIO_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_GIO_UNIX_LIBS"; then + pkg_cv_OT_DEP_GIO_UNIX_LIBS="$OT_DEP_GIO_UNIX_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$GIO_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$GIO_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_GIO_UNIX_LIBS=`$PKG_CONFIG --libs "$GIO_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_GIO_UNIX_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$GIO_DEPENDENCY" 2>&1` + else + OT_DEP_GIO_UNIX_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$GIO_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_GIO_UNIX_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($GIO_DEPENDENCY) were not met: + +$OT_DEP_GIO_UNIX_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_GIO_UNIX_CFLAGS +and OT_DEP_GIO_UNIX_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_GIO_UNIX_CFLAGS +and OT_DEP_GIO_UNIX_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_GIO_UNIX_CFLAGS=$pkg_cv_OT_DEP_GIO_UNIX_CFLAGS + OT_DEP_GIO_UNIX_LIBS=$pkg_cv_OT_DEP_GIO_UNIX_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_LZMA" >&5 +$as_echo_n "checking for OT_DEP_LZMA... " >&6; } + +if test -n "$OT_DEP_LZMA_CFLAGS"; then + pkg_cv_OT_DEP_LZMA_CFLAGS="$OT_DEP_LZMA_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"liblzma >= 5.0.5\""; } >&5 + ($PKG_CONFIG --exists --print-errors "liblzma >= 5.0.5") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LZMA_CFLAGS=`$PKG_CONFIG --cflags "liblzma >= 5.0.5" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_LZMA_LIBS"; then + pkg_cv_OT_DEP_LZMA_LIBS="$OT_DEP_LZMA_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"liblzma >= 5.0.5\""; } >&5 + ($PKG_CONFIG --exists --print-errors "liblzma >= 5.0.5") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LZMA_LIBS=`$PKG_CONFIG --libs "liblzma >= 5.0.5" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_LZMA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "liblzma >= 5.0.5" 2>&1` + else + OT_DEP_LZMA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "liblzma >= 5.0.5" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_LZMA_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (liblzma >= 5.0.5) were not met: + +$OT_DEP_LZMA_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_LZMA_CFLAGS +and OT_DEP_LZMA_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_LZMA_CFLAGS +and OT_DEP_LZMA_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_LZMA_CFLAGS=$pkg_cv_OT_DEP_LZMA_CFLAGS + OT_DEP_LZMA_LIBS=$pkg_cv_OT_DEP_LZMA_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_ZLIB" >&5 +$as_echo_n "checking for OT_DEP_ZLIB... " >&6; } + +if test -n "$OT_DEP_ZLIB_CFLAGS"; then + pkg_cv_OT_DEP_ZLIB_CFLAGS="$OT_DEP_ZLIB_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5 + ($PKG_CONFIG --exists --print-errors "zlib") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_ZLIB_CFLAGS=`$PKG_CONFIG --cflags "zlib" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_ZLIB_LIBS"; then + pkg_cv_OT_DEP_ZLIB_LIBS="$OT_DEP_ZLIB_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"zlib\""; } >&5 + ($PKG_CONFIG --exists --print-errors "zlib") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_ZLIB_LIBS=`$PKG_CONFIG --libs "zlib" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_ZLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "zlib" 2>&1` + else + OT_DEP_ZLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "zlib" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_ZLIB_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (zlib) were not met: + +$OT_DEP_ZLIB_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_ZLIB_CFLAGS +and OT_DEP_ZLIB_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_ZLIB_CFLAGS +and OT_DEP_ZLIB_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_ZLIB_CFLAGS=$pkg_cv_OT_DEP_ZLIB_CFLAGS + OT_DEP_ZLIB_LIBS=$pkg_cv_OT_DEP_ZLIB_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_E2P" >&5 +$as_echo_n "checking for OT_DEP_E2P... " >&6; } + +if test -n "$OT_DEP_E2P_CFLAGS"; then + pkg_cv_OT_DEP_E2P_CFLAGS="$OT_DEP_E2P_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"e2p\""; } >&5 + ($PKG_CONFIG --exists --print-errors "e2p") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_E2P_CFLAGS=`$PKG_CONFIG --cflags "e2p" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_E2P_LIBS"; then + pkg_cv_OT_DEP_E2P_LIBS="$OT_DEP_E2P_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"e2p\""; } >&5 + ($PKG_CONFIG --exists --print-errors "e2p") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_E2P_LIBS=`$PKG_CONFIG --libs "e2p" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_E2P_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "e2p" 2>&1` + else + OT_DEP_E2P_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "e2p" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_E2P_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (e2p) were not met: + +$OT_DEP_E2P_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_E2P_CFLAGS +and OT_DEP_E2P_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_E2P_CFLAGS +and OT_DEP_E2P_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_E2P_CFLAGS=$pkg_cv_OT_DEP_E2P_CFLAGS + OT_DEP_E2P_LIBS=$pkg_cv_OT_DEP_E2P_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + +CURL_DEPENDENCY=7.29.0 + +# Check whether --with-curl was given. +if test "${with_curl+set}" = set; then : + withval=$with_curl; +else + with_curl=no +fi + +if test x$with_curl != xno ; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_CURL" >&5 +$as_echo_n "checking for OT_DEP_CURL... " >&6; } + +if test -n "$OT_DEP_CURL_CFLAGS"; then + pkg_cv_OT_DEP_CURL_CFLAGS="$OT_DEP_CURL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcurl >= \$CURL_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libcurl >= $CURL_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_CURL_CFLAGS=`$PKG_CONFIG --cflags "libcurl >= $CURL_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_CURL_LIBS"; then + pkg_cv_OT_DEP_CURL_LIBS="$OT_DEP_CURL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcurl >= \$CURL_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libcurl >= $CURL_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_CURL_LIBS=`$PKG_CONFIG --libs "libcurl >= $CURL_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_CURL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcurl >= $CURL_DEPENDENCY" 2>&1` + else + OT_DEP_CURL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcurl >= $CURL_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_CURL_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (libcurl >= $CURL_DEPENDENCY) were not met: + +$OT_DEP_CURL_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_CURL_CFLAGS +and OT_DEP_CURL_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_CURL_CFLAGS +and OT_DEP_CURL_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_CURL_CFLAGS=$pkg_cv_OT_DEP_CURL_CFLAGS + OT_DEP_CURL_LIBS=$pkg_cv_OT_DEP_CURL_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + with_curl=yes + +$as_echo "#define HAVE_LIBCURL 1" >>confdefs.h + + with_soup_default=yes + +else + with_soup_default=check +fi + if test x$with_curl != xno; then + USE_CURL_TRUE= + USE_CURL_FALSE='#' +else + USE_CURL_TRUE='#' + USE_CURL_FALSE= +fi + +if test x$with_curl = xyes; then OSTREE_FEATURES="$OSTREE_FEATURES libcurl"; fi +# Check whether --enable-http2 was given. +if test "${enable_http2+set}" = set; then : + enableval=$enable_http2; +else + enable_http2=yes +fi + +if test x$enable_http2 != xno ; then : + + +$as_echo "#define BUILDOPT_HTTP2 1" >>confdefs.h + + +else + + OSTREE_FEATURES="$OSTREE_FEATURES no-http2" + +fi + +SOUP_DEPENDENCY="libsoup-2.4 >= 2.39.1" + +# Check whether --with-soup was given. +if test "${with_soup+set}" = set; then : + withval=$with_soup; +else + with_soup=$with_soup_default +fi + +if test x$with_soup != xno; then : + + # Check whether --enable-libsoup_client_certs was given. +if test "${enable_libsoup_client_certs+set}" = set; then : + enableval=$enable_libsoup_client_certs; +else + enable_libsoup_client_certs=auto +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $SOUP_DEPENDENCY" >&5 +$as_echo_n "checking for $SOUP_DEPENDENCY... " >&6; } + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$SOUP_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$SOUP_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + have_soup=yes +else + have_soup=no +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_soup" >&5 +$as_echo "$have_soup" >&6; } + if test x$have_soup = xno && test x$with_soup != xcheck; then : + + as_fn_error $? "libsoup is enabled but could not be found" "$LINENO" 5 + +fi + if test x$have_soup = xyes; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_SOUP" >&5 +$as_echo_n "checking for OT_DEP_SOUP... " >&6; } + +if test -n "$OT_DEP_SOUP_CFLAGS"; then + pkg_cv_OT_DEP_SOUP_CFLAGS="$OT_DEP_SOUP_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$SOUP_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$SOUP_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_SOUP_CFLAGS=`$PKG_CONFIG --cflags "$SOUP_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_SOUP_LIBS"; then + pkg_cv_OT_DEP_SOUP_LIBS="$OT_DEP_SOUP_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$SOUP_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$SOUP_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_SOUP_LIBS=`$PKG_CONFIG --libs "$SOUP_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_SOUP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$SOUP_DEPENDENCY" 2>&1` + else + OT_DEP_SOUP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$SOUP_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_SOUP_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($SOUP_DEPENDENCY) were not met: + +$OT_DEP_SOUP_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_SOUP_CFLAGS +and OT_DEP_SOUP_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_SOUP_CFLAGS +and OT_DEP_SOUP_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_SOUP_CFLAGS=$pkg_cv_OT_DEP_SOUP_CFLAGS + OT_DEP_SOUP_LIBS=$pkg_cv_OT_DEP_SOUP_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + +$as_echo "#define HAVE_LIBSOUP 1" >>confdefs.h + + with_soup=yes + save_CFLAGS=$CFLAGS + CFLAGS=$OT_DEP_SOUP_CFLAGS + have_libsoup_client_certs=no + ac_fn_c_check_decl "$LINENO" "SOUP_SESSION_TLS_INTERACTION" "ac_cv_have_decl_SOUP_SESSION_TLS_INTERACTION" "#include +" +if test "x$ac_cv_have_decl_SOUP_SESSION_TLS_INTERACTION" = xyes; then : + + +$as_echo "#define HAVE_LIBSOUP_CLIENT_CERTS 1" >>confdefs.h + + have_libsoup_client_certs=yes + +fi + + if test x$enable_libsoup_client_certs = xyes && test x$have_libsoup_client_certs != xyes; then : + + as_fn_error $? "libsoup client certs explicitly requested but not found" "$LINENO" 5 + +fi + CFLAGS=$save_CFLAGS + +else + + with_soup=no + +fi + +else + with_soup=no +fi +if test x$with_soup != xno; then OSTREE_FEATURES="$OSTREE_FEATURES libsoup"; fi + if test x$with_soup != xno; then + USE_LIBSOUP_TRUE= + USE_LIBSOUP_FALSE='#' +else + USE_LIBSOUP_TRUE='#' + USE_LIBSOUP_FALSE= +fi + + if test x$have_libsoup_client_certs = xyes; then + HAVE_LIBSOUP_CLIENT_CERTS_TRUE= + HAVE_LIBSOUP_CLIENT_CERTS_FALSE='#' +else + HAVE_LIBSOUP_CLIENT_CERTS_TRUE='#' + HAVE_LIBSOUP_CLIENT_CERTS_FALSE= +fi + + +# Check whether --enable-trivial-httpd-cmdline was given. +if test "${enable_trivial_httpd_cmdline+set}" = set; then : + enableval=$enable_trivial_httpd_cmdline; +else + enable_trivial_httpd_cmdline=no +fi + +if test x$enable_trivial_httpd_cmdline = xyes; then : + +$as_echo "#define BUILDOPT_ENABLE_TRIVIAL_HTTPD_CMDLINE 1" >>confdefs.h + + +fi + +if test x$with_curl = xyes && test x$with_soup = xno; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Curl enabled, but libsoup is not; libsoup is needed for tests (make check, etc.)" >&5 +$as_echo "$as_me: WARNING: Curl enabled, but libsoup is not; libsoup is needed for tests (make check, etc.)" >&2;} + +fi + if test x$with_curl != xno || test x$with_soup != xno; then + USE_CURL_OR_SOUP_TRUE= + USE_CURL_OR_SOUP_FALSE='#' +else + USE_CURL_OR_SOUP_TRUE='#' + USE_CURL_OR_SOUP_FALSE= +fi + +if test x$with_curl != xno || test x$with_soup != xno; then : + +$as_echo "#define HAVE_LIBCURL_OR_LIBSOUP 1" >>confdefs.h + +fi +if test x$with_curl = xyes; then : + fetcher_backend=curl +elif test x$with_soup = xyes; then : + fetcher_backend=libsoup +else + fetcher_backend=none +fi + + + + + + # Check whether --enable-introspection was given. +if test "${enable_introspection+set}" = set; then : + enableval=$enable_introspection; +else + enable_introspection=auto +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gobject-introspection" >&5 +$as_echo_n "checking for gobject-introspection... " >&6; } + + case $enable_introspection in #( + no) : + found_introspection="no (disabled, use --enable-introspection to enable)" + ;; #( + yes) : + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gobject-introspection-1.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gobject-introspection-1.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + : +else + as_fn_error $? "gobject-introspection-1.0 is not installed" "$LINENO" 5 +fi + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gobject-introspection-1.0 >= 1.34.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gobject-introspection-1.0 >= 1.34.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + found_introspection=yes +else + as_fn_error $? "You need to have gobject-introspection >= 1.34.0 installed to build libostree" "$LINENO" 5 +fi + ;; #( + auto) : + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gobject-introspection-1.0 >= 1.34.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gobject-introspection-1.0 >= 1.34.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + found_introspection=yes +else + found_introspection=no +fi + enable_introspection=$found_introspection + ;; #( + *) : + as_fn_error $? "invalid argument passed to --enable-introspection, should be one of [no/auto/yes]" "$LINENO" 5 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $found_introspection" >&5 +$as_echo "$found_introspection" >&6; } + + + EXP_VAR=_GI_EXP_DATADIR + FROM_VAR="$datadir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + _GI_EXP_DATADIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + + EXP_VAR=_GI_EXP_LIBDIR + FROM_VAR="$libdir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + _GI_EXP_LIBDIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + + INTROSPECTION_SCANNER= + INTROSPECTION_COMPILER= + INTROSPECTION_GENERATE= + INTROSPECTION_GIRDIR= + INTROSPECTION_TYPELIBDIR= + if test "x$found_introspection" = "xyes"; then + INTROSPECTION_SCANNER=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0` + INTROSPECTION_COMPILER=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0` + INTROSPECTION_GENERATE=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0` + INTROSPECTION_GIRDIR=`$PKG_CONFIG --define-variable=datadir="${_GI_EXP_DATADIR}" --variable=girdir gobject-introspection-1.0` + INTROSPECTION_TYPELIBDIR="$($PKG_CONFIG --define-variable=libdir="${_GI_EXP_LIBDIR}" --variable=typelibdir gobject-introspection-1.0)" + INTROSPECTION_CFLAGS=`$PKG_CONFIG --cflags gobject-introspection-1.0` + INTROSPECTION_LIBS=`$PKG_CONFIG --libs gobject-introspection-1.0` + INTROSPECTION_MAKEFILE=$PKG_CONFIG_SYSROOT_DIR`$PKG_CONFIG --variable=datadir gobject-introspection-1.0`/gobject-introspection-1.0/Makefile.introspection + fi + + + + + + + + + + if test "x$found_introspection" = "xyes"; then + HAVE_INTROSPECTION_TRUE= + HAVE_INTROSPECTION_FALSE='#' +else + HAVE_INTROSPECTION_TRUE='#' + HAVE_INTROSPECTION_FALSE= +fi + + + + + if test "x$found_introspection" = xyes; then + BUILDOPT_INTROSPECTION_TRUE= + BUILDOPT_INTROSPECTION_FALSE='#' +else + BUILDOPT_INTROSPECTION_TRUE='#' + BUILDOPT_INTROSPECTION_FALSE= +fi + + +LIBGPGME_DEPENDENCY="1.1.8" + +# Check whether --with-gpgme was given. +if test "${with_gpgme+set}" = set; then : + withval=$with_gpgme; +else + with_gpgme=yes +fi + + +# Check whether --with-gpgme-prefix was given. +if test "${with_gpgme_prefix+set}" = set; then : + withval=$with_gpgme_prefix; gpgme_config_prefix="$withval" +else + gpgme_config_prefix="" +fi + + if test x"${GPGME_CONFIG}" = x ; then + if test x"${gpgme_config_prefix}" != x ; then + GPGME_CONFIG="${gpgme_config_prefix}/bin/gpgme-config" + else + case "${SYSROOT}" in + /*) + if test -x "${SYSROOT}/bin/gpgme-config" ; then + GPGME_CONFIG="${SYSROOT}/bin/gpgme-config" + fi + ;; + '') + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring \$SYSROOT as it is not an absolute path." >&5 +$as_echo "$as_me: WARNING: Ignoring \$SYSROOT as it is not an absolute path." >&2;} + ;; + esac + fi + fi + + use_gpgrt_config="" + if test x"${GPGME_CONFIG}" = x -a x"$GPGRT_CONFIG" != x -a "$GPGRT_CONFIG" != "no"; then + if $GPGRT_CONFIG gpgme --exists; then + GPGME_CONFIG="$GPGRT_CONFIG gpgme" + { $as_echo "$as_me:${as_lineno-$LINENO}: Use gpgrt-config as gpgme-config" >&5 +$as_echo "$as_me: Use gpgrt-config as gpgme-config" >&6;} + use_gpgrt_config=yes + fi + fi + if test -z "$use_gpgrt_config"; then + # Extract the first word of "gpgme-config", so it can be a program name with args. +set dummy gpgme-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GPGME_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GPGME_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_GPGME_CONFIG="$GPGME_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GPGME_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_GPGME_CONFIG" && ac_cv_path_GPGME_CONFIG="no" + ;; +esac +fi +GPGME_CONFIG=$ac_cv_path_GPGME_CONFIG +if test -n "$GPGME_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GPGME_CONFIG" >&5 +$as_echo "$GPGME_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + + if test "$GPGME_CONFIG" != "no" ; then + if test -z "$use_gpgrt_config"; then + gpgme_version=`$GPGME_CONFIG --version` + else + gpgme_version=`$GPGME_CONFIG --modversion` + fi + fi + gpgme_version_major=`echo $gpgme_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1/'` + gpgme_version_minor=`echo $gpgme_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\2/'` + gpgme_version_micro=`echo $gpgme_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\3/'` + +if test x$with_gpgme != xno; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_GPGME" >&5 +$as_echo_n "checking for OT_DEP_GPGME... " >&6; } + +if test -n "$OT_DEP_GPGME_CFLAGS"; then + pkg_cv_OT_DEP_GPGME_CFLAGS="$OT_DEP_GPGME_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gpgme-pthread >= \$LIBGPGME_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gpgme-pthread >= $LIBGPGME_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_GPGME_CFLAGS=`$PKG_CONFIG --cflags "gpgme-pthread >= $LIBGPGME_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_GPGME_LIBS"; then + pkg_cv_OT_DEP_GPGME_LIBS="$OT_DEP_GPGME_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gpgme-pthread >= \$LIBGPGME_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gpgme-pthread >= $LIBGPGME_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_GPGME_LIBS=`$PKG_CONFIG --libs "gpgme-pthread >= $LIBGPGME_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_GPGME_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gpgme-pthread >= $LIBGPGME_DEPENDENCY" 2>&1` + else + OT_DEP_GPGME_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gpgme-pthread >= $LIBGPGME_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_GPGME_PKG_ERRORS" >&5 + + + + tmp=$LIBGPGME_DEPENDENCY + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_gpgme_api=0 + min_gpgme_version="$tmp" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GPGME pthread - version >= $min_gpgme_version" >&5 +$as_echo_n "checking for GPGME pthread - version >= $min_gpgme_version... " >&6; } + ok=no + if test "$GPGME_CONFIG" != "no" ; then + if `$GPGME_CONFIG --thread=pthread 2> /dev/null` ; then + req_major=`echo $min_gpgme_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + if test "$gpgme_version_major" -gt "$req_major"; then + ok=yes + else + if test "$gpgme_version_major" -eq "$req_major"; then + if test "$gpgme_version_minor" -gt "$req_minor"; then + ok=yes + else + if test "$gpgme_version_minor" -eq "$req_minor"; then + if test "$gpgme_version_micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent GPGME, we should also check that the + # API is compatible. + if test "$req_gpgme_api" -gt 0 ; then + tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + if test "$req_gpgme_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + GPGME_PTHREAD_CFLAGS=`$GPGME_CONFIG --thread=pthread --cflags` + GPGME_PTHREAD_LIBS=`$GPGME_CONFIG --thread=pthread --libs` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_gpgme=yes + + if test -z "$use_gpgrt_config"; then + gpgme_config_host=`$GPGME_CONFIG --host 2>/dev/null || echo none` + else + gpgme_config_host=`$GPGME_CONFIG --variable=host 2>/dev/null || echo none` + fi + if test x"$gpgme_config_host" != xnone ; then + if test x"$gpgme_config_host" != x"$host" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +*** +*** The config script \"$GPGME_CONFIG\" was +*** built for $gpgme_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-gpgme-prefix +*** to specify a matching config script or use \$SYSROOT. +***" >&5 +$as_echo "$as_me: WARNING: +*** +*** The config script \"$GPGME_CONFIG\" was +*** built for $gpgme_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-gpgme-prefix +*** to specify a matching config script or use \$SYSROOT. +***" >&2;} + gpg_config_script_warn="$gpg_config_script_warn gpgme" + fi + fi + + else + GPGME_PTHREAD_CFLAGS="" + GPGME_PTHREAD_LIBS="" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_gpgme=no + fi + + + + + +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + + tmp=$LIBGPGME_DEPENDENCY + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_gpgme_api=0 + min_gpgme_version="$tmp" + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GPGME pthread - version >= $min_gpgme_version" >&5 +$as_echo_n "checking for GPGME pthread - version >= $min_gpgme_version... " >&6; } + ok=no + if test "$GPGME_CONFIG" != "no" ; then + if `$GPGME_CONFIG --thread=pthread 2> /dev/null` ; then + req_major=`echo $min_gpgme_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + if test "$gpgme_version_major" -gt "$req_major"; then + ok=yes + else + if test "$gpgme_version_major" -eq "$req_major"; then + if test "$gpgme_version_minor" -gt "$req_minor"; then + ok=yes + else + if test "$gpgme_version_minor" -eq "$req_minor"; then + if test "$gpgme_version_micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent GPGME, we should also check that the + # API is compatible. + if test "$req_gpgme_api" -gt 0 ; then + tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + if test "$req_gpgme_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + GPGME_PTHREAD_CFLAGS=`$GPGME_CONFIG --thread=pthread --cflags` + GPGME_PTHREAD_LIBS=`$GPGME_CONFIG --thread=pthread --libs` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_gpgme=yes + + if test -z "$use_gpgrt_config"; then + gpgme_config_host=`$GPGME_CONFIG --host 2>/dev/null || echo none` + else + gpgme_config_host=`$GPGME_CONFIG --variable=host 2>/dev/null || echo none` + fi + if test x"$gpgme_config_host" != xnone ; then + if test x"$gpgme_config_host" != x"$host" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +*** +*** The config script \"$GPGME_CONFIG\" was +*** built for $gpgme_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-gpgme-prefix +*** to specify a matching config script or use \$SYSROOT. +***" >&5 +$as_echo "$as_me: WARNING: +*** +*** The config script \"$GPGME_CONFIG\" was +*** built for $gpgme_config_host and thus may not match the +*** used host $host. +*** You may want to use the configure option --with-gpgme-prefix +*** to specify a matching config script or use \$SYSROOT. +***" >&2;} + gpg_config_script_warn="$gpg_config_script_warn gpgme" + fi + fi + + else + GPGME_PTHREAD_CFLAGS="" + GPGME_PTHREAD_LIBS="" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_gpgme=no + fi + + + + + +else + OT_DEP_GPGME_CFLAGS=$pkg_cv_OT_DEP_GPGME_CFLAGS + OT_DEP_GPGME_LIBS=$pkg_cv_OT_DEP_GPGME_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_gpgme=yes +fi + if test x$have_gpgme = xno ; then : + + as_fn_error $? "Need GPGME_PTHREAD version $LIBGPGME_DEPENDENCY or later" "$LINENO" 5 + +fi + OSTREE_FEATURES="$OSTREE_FEATURES gpgme" + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_GPG_ERROR" >&5 +$as_echo_n "checking for OT_DEP_GPG_ERROR... " >&6; } + +if test -n "$OT_DEP_GPG_ERROR_CFLAGS"; then + pkg_cv_OT_DEP_GPG_ERROR_CFLAGS="$OT_DEP_GPG_ERROR_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gpg-error\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gpg-error") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_GPG_ERROR_CFLAGS=`$PKG_CONFIG --cflags "gpg-error" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_GPG_ERROR_LIBS"; then + pkg_cv_OT_DEP_GPG_ERROR_LIBS="$OT_DEP_GPG_ERROR_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gpg-error\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gpg-error") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_GPG_ERROR_LIBS=`$PKG_CONFIG --libs "gpg-error" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_GPG_ERROR_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gpg-error" 2>&1` + else + OT_DEP_GPG_ERROR_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gpg-error" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_GPG_ERROR_PKG_ERRORS" >&5 + + + # Extract the first word of "gpg-error-config", so it can be a program name with args. +set dummy gpg-error-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GPG_ERROR_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GPG_ERROR_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_GPG_ERROR_CONFIG="$GPG_ERROR_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GPG_ERROR_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_GPG_ERROR_CONFIG" && ac_cv_path_GPG_ERROR_CONFIG="as_fn_error $? "Missing gpg-error-config" "$LINENO" 5" + ;; +esac +fi +GPG_ERROR_CONFIG=$ac_cv_path_GPG_ERROR_CONFIG +if test -n "$GPG_ERROR_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GPG_ERROR_CONFIG" >&5 +$as_echo "$GPG_ERROR_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + OT_DEP_GPG_ERROR_CFLAGS="$( $GPG_ERROR_CONFIG --cflags )" + OT_DEP_GPG_ERROR_LIBS="$( $GPG_ERROR_CONFIG --libs )" + +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + # Extract the first word of "gpg-error-config", so it can be a program name with args. +set dummy gpg-error-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GPG_ERROR_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GPG_ERROR_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_GPG_ERROR_CONFIG="$GPG_ERROR_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GPG_ERROR_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_GPG_ERROR_CONFIG" && ac_cv_path_GPG_ERROR_CONFIG="as_fn_error $? "Missing gpg-error-config" "$LINENO" 5" + ;; +esac +fi +GPG_ERROR_CONFIG=$ac_cv_path_GPG_ERROR_CONFIG +if test -n "$GPG_ERROR_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GPG_ERROR_CONFIG" >&5 +$as_echo "$GPG_ERROR_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + OT_DEP_GPG_ERROR_CFLAGS="$( $GPG_ERROR_CONFIG --cflags )" + OT_DEP_GPG_ERROR_LIBS="$( $GPG_ERROR_CONFIG --libs )" + +else + OT_DEP_GPG_ERROR_CFLAGS=$pkg_cv_OT_DEP_GPG_ERROR_CFLAGS + OT_DEP_GPG_ERROR_LIBS=$pkg_cv_OT_DEP_GPG_ERROR_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + OT_DEP_GPGME_CFLAGS="${OT_DEP_GPGME_CFLAGS} ${OT_DEP_GPG_ERROR_CFLAGS}" + OT_DEP_GPGME_LIBS="${OT_DEP_GPGME_LIBS} ${OT_DEP_GPG_ERROR_LIBS}" + +else + + +$as_echo "#define OSTREE_DISABLE_GPGME 1" >>confdefs.h + + with_gpgme=no + + +fi + if test "x$have_gpgme" = xyes; then + USE_GPGME_TRUE= + USE_GPGME_FALSE='#' +else + USE_GPGME_TRUE='#' + USE_GPGME_FALSE= +fi + + + +LIBSODIUM_DEPENDENCY="1.0.14" + +# Check whether --with-ed25519_libsodium was given. +if test "${with_ed25519_libsodium+set}" = set; then : + withval=$with_ed25519_libsodium; +else + with_ed25519_libsodium=no +fi + +if test x$with_ed25519_libsodium != xno; then : + + +$as_echo "#define HAVE_LIBSODIUM 1" >>confdefs.h + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_LIBSODIUM" >&5 +$as_echo_n "checking for OT_DEP_LIBSODIUM... " >&6; } + +if test -n "$OT_DEP_LIBSODIUM_CFLAGS"; then + pkg_cv_OT_DEP_LIBSODIUM_CFLAGS="$OT_DEP_LIBSODIUM_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium >= \$LIBSODIUM_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsodium >= $LIBSODIUM_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LIBSODIUM_CFLAGS=`$PKG_CONFIG --cflags "libsodium >= $LIBSODIUM_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_LIBSODIUM_LIBS"; then + pkg_cv_OT_DEP_LIBSODIUM_LIBS="$OT_DEP_LIBSODIUM_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium >= \$LIBSODIUM_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsodium >= $LIBSODIUM_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LIBSODIUM_LIBS=`$PKG_CONFIG --libs "libsodium >= $LIBSODIUM_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsodium >= $LIBSODIUM_DEPENDENCY" 2>&1` + else + OT_DEP_LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsodium >= $LIBSODIUM_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_LIBSODIUM_PKG_ERRORS" >&5 + + have_libsodium=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_libsodium=no +else + OT_DEP_LIBSODIUM_CFLAGS=$pkg_cv_OT_DEP_LIBSODIUM_CFLAGS + OT_DEP_LIBSODIUM_LIBS=$pkg_cv_OT_DEP_LIBSODIUM_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_libsodium=yes +fi + if test x$have_libsodium = xno ; then : + + as_fn_error $? "Need LIBSODIUM version $LIBSODIUM_DEPENDENCY or later" "$LINENO" 5 + +fi + OSTREE_FEATURES="$OSTREE_FEATURES sign-ed25519" + +else + with_ed25519_libsodium=no +fi + if test "x$have_libsodium" = xyes; then + USE_LIBSODIUM_TRUE= + USE_LIBSODIUM_FALSE='#' +else + USE_LIBSODIUM_TRUE='#' + USE_LIBSODIUM_FALSE= +fi + + +LIBARCHIVE_DEPENDENCY="libarchive >= 2.8.0" +# What's in RHEL7.2. +FUSE_DEPENDENCY="fuse >= 2.9.2" + +for ac_header in linux/fsverity.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "linux/fsverity.h" "ac_cv_header_linux_fsverity_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_fsverity_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINUX_FSVERITY_H 1 +_ACEOF + +fi + +done + +if test x$ac_cv_header_linux_fsverity_h = xyes ; then : + OSTREE_FEATURES="$OSTREE_FEATURES ex-fsverity" +fi + +# check for gtk-doc + + + + + gtk_doc_requires="gtk-doc >= 1.15" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gtk-doc" >&5 +$as_echo_n "checking for gtk-doc... " >&6; } + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$gtk_doc_requires\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$gtk_doc_requires") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + have_gtk_doc=yes +else + have_gtk_doc=no +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gtk_doc" >&5 +$as_echo "$have_gtk_doc" >&6; } + + if test "$have_gtk_doc" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: + You will not be able to create source packages with 'make dist' + because $gtk_doc_requires is not found." >&5 +$as_echo "$as_me: WARNING: + You will not be able to create source packages with 'make dist' + because $gtk_doc_requires is not found." >&2;} + fi + + # Extract the first word of "gtkdoc-check", so it can be a program name with args. +set dummy gtkdoc-check; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_GTKDOC_CHECK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GTKDOC_CHECK"; then + ac_cv_prog_GTKDOC_CHECK="$GTKDOC_CHECK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_GTKDOC_CHECK="gtkdoc-check.test" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GTKDOC_CHECK=$ac_cv_prog_GTKDOC_CHECK +if test -n "$GTKDOC_CHECK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GTKDOC_CHECK" >&5 +$as_echo "$GTKDOC_CHECK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + # Extract the first word of "gtkdoc-check", so it can be a program name with args. +set dummy gtkdoc-check; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GTKDOC_CHECK_PATH+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GTKDOC_CHECK_PATH in + [\\/]* | ?:[\\/]*) + ac_cv_path_GTKDOC_CHECK_PATH="$GTKDOC_CHECK_PATH" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GTKDOC_CHECK_PATH="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +GTKDOC_CHECK_PATH=$ac_cv_path_GTKDOC_CHECK_PATH +if test -n "$GTKDOC_CHECK_PATH"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GTKDOC_CHECK_PATH" >&5 +$as_echo "$GTKDOC_CHECK_PATH" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + for ac_prog in gtkdoc-rebase +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GTKDOC_REBASE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GTKDOC_REBASE in + [\\/]* | ?:[\\/]*) + ac_cv_path_GTKDOC_REBASE="$GTKDOC_REBASE" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GTKDOC_REBASE="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +GTKDOC_REBASE=$ac_cv_path_GTKDOC_REBASE +if test -n "$GTKDOC_REBASE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GTKDOC_REBASE" >&5 +$as_echo "$GTKDOC_REBASE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$GTKDOC_REBASE" && break +done +test -n "$GTKDOC_REBASE" || GTKDOC_REBASE="true" + + # Extract the first word of "gtkdoc-mkpdf", so it can be a program name with args. +set dummy gtkdoc-mkpdf; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GTKDOC_MKPDF+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GTKDOC_MKPDF in + [\\/]* | ?:[\\/]*) + ac_cv_path_GTKDOC_MKPDF="$GTKDOC_MKPDF" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GTKDOC_MKPDF="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +GTKDOC_MKPDF=$ac_cv_path_GTKDOC_MKPDF +if test -n "$GTKDOC_MKPDF"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GTKDOC_MKPDF" >&5 +$as_echo "$GTKDOC_MKPDF" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + +# Check whether --with-html-dir was given. +if test "${with_html_dir+set}" = set; then : + withval=$with_html_dir; +else + with_html_dir='${datadir}/gtk-doc/html' +fi + + HTML_DIR="$with_html_dir" + + + # Check whether --enable-gtk-doc was given. +if test "${enable_gtk_doc+set}" = set; then : + enableval=$enable_gtk_doc; +else + enable_gtk_doc=no +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build gtk-doc documentation" >&5 +$as_echo_n "checking whether to build gtk-doc documentation... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gtk_doc" >&5 +$as_echo "$enable_gtk_doc" >&6; } + + if test "x$enable_gtk_doc" = "xyes" && test "$have_gtk_doc" = "no"; then + as_fn_error $? " + You must have $gtk_doc_requires installed to build documentation for + $PACKAGE_NAME. Please install gtk-doc or disable building the + documentation by adding '--disable-gtk-doc' to '$0'." "$LINENO" 5 + fi + + if test "x$PACKAGE_NAME" != "xglib"; then + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTKDOC_DEPS" >&5 +$as_echo_n "checking for GTKDOC_DEPS... " >&6; } + +if test -n "$GTKDOC_DEPS_CFLAGS"; then + pkg_cv_GTKDOC_DEPS_CFLAGS="$GTKDOC_DEPS_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GTKDOC_DEPS_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GTKDOC_DEPS_LIBS"; then + pkg_cv_GTKDOC_DEPS_LIBS="$GTKDOC_DEPS_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GTKDOC_DEPS_LIBS=`$PKG_CONFIG --libs "glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GTKDOC_DEPS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0" 2>&1` + else + GTKDOC_DEPS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GTKDOC_DEPS_PKG_ERRORS" >&5 + + : +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + : +else + GTKDOC_DEPS_CFLAGS=$pkg_cv_GTKDOC_DEPS_CFLAGS + GTKDOC_DEPS_LIBS=$pkg_cv_GTKDOC_DEPS_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + fi + + # Check whether --enable-gtk-doc-html was given. +if test "${enable_gtk_doc_html+set}" = set; then : + enableval=$enable_gtk_doc_html; +else + enable_gtk_doc_html=yes +fi + + # Check whether --enable-gtk-doc-pdf was given. +if test "${enable_gtk_doc_pdf+set}" = set; then : + enableval=$enable_gtk_doc_pdf; +else + enable_gtk_doc_pdf=no +fi + + + if test -z "$GTKDOC_MKPDF"; then + enable_gtk_doc_pdf=no + fi + + if test -z "$AM_DEFAULT_VERBOSITY"; then + AM_DEFAULT_VERBOSITY=1 + fi + + + if test x$have_gtk_doc = xyes; then + HAVE_GTK_DOC_TRUE= + HAVE_GTK_DOC_FALSE='#' +else + HAVE_GTK_DOC_TRUE='#' + HAVE_GTK_DOC_FALSE= +fi + + if test x$enable_gtk_doc = xyes; then + ENABLE_GTK_DOC_TRUE= + ENABLE_GTK_DOC_FALSE='#' +else + ENABLE_GTK_DOC_TRUE='#' + ENABLE_GTK_DOC_FALSE= +fi + + if test x$enable_gtk_doc_html = xyes; then + GTK_DOC_BUILD_HTML_TRUE= + GTK_DOC_BUILD_HTML_FALSE='#' +else + GTK_DOC_BUILD_HTML_TRUE='#' + GTK_DOC_BUILD_HTML_FALSE= +fi + + if test x$enable_gtk_doc_pdf = xyes; then + GTK_DOC_BUILD_PDF_TRUE= + GTK_DOC_BUILD_PDF_FALSE='#' +else + GTK_DOC_BUILD_PDF_TRUE='#' + GTK_DOC_BUILD_PDF_FALSE= +fi + + if test -n "$LIBTOOL"; then + GTK_DOC_USE_LIBTOOL_TRUE= + GTK_DOC_USE_LIBTOOL_FALSE='#' +else + GTK_DOC_USE_LIBTOOL_TRUE='#' + GTK_DOC_USE_LIBTOOL_FALSE= +fi + + if test -n "$GTKDOC_REBASE"; then + GTK_DOC_USE_REBASE_TRUE= + GTK_DOC_USE_REBASE_FALSE='#' +else + GTK_DOC_USE_REBASE_TRUE='#' + GTK_DOC_USE_REBASE_FALSE= +fi + + + + +# Check whether --enable-man was given. +if test "${enable_man+set}" = set; then : + enableval=$enable_man; +else + enable_man=maybe +fi + + +if test "$enable_man" != no; then : + + # Extract the first word of "xsltproc", so it can be a program name with args. +set dummy xsltproc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_XSLTPROC+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $XSLTPROC in + [\\/]* | ?:[\\/]*) + ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_XSLTPROC="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +XSLTPROC=$ac_cv_path_XSLTPROC +if test -n "$XSLTPROC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 +$as_echo "$XSLTPROC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -z "$XSLTPROC"; then : + + if test "$enable_man" = yes; then : + + as_fn_error $? "xsltproc is required for --enable-man" "$LINENO" 5 + +fi + enable_man=no + +else + + enable_man=yes + +fi + +fi + if test "$enable_man" != no; then + ENABLE_MAN_TRUE= + ENABLE_MAN_FALSE='#' +else + ENABLE_MAN_TRUE='#' + ENABLE_MAN_FALSE= +fi + + +# Check whether --enable-rust was given. +if test "${enable_rust+set}" = set; then : + enableval=$enable_rust; +else + enable_rust=no; rust_debug_release=no +fi + + +if test "$enable_rust" = yes; then : + + # Extract the first word of "cargo", so it can be a program name with args. +set dummy cargo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_cargo+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $cargo in + [\\/]* | ?:[\\/]*) + ac_cv_path_cargo="$cargo" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_cargo="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +cargo=$ac_cv_path_cargo +if test -n "$cargo"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cargo" >&5 +$as_echo "$cargo" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -z "$cargo"; then : + as_fn_error $? "cargo is required for --enable-rust" "$LINENO" 5 +fi + # Extract the first word of "rustc", so it can be a program name with args. +set dummy rustc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_rustc+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $rustc in + [\\/]* | ?:[\\/]*) + ac_cv_path_rustc="$rustc" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_rustc="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +rustc=$ac_cv_path_rustc +if test -n "$rustc"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $rustc" >&5 +$as_echo "$rustc" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -z "$rustc"; then : + as_fn_error $? "rustc is required for --enable-rust" "$LINENO" 5 +fi + + + # Check whether --enable-rust-debug was given. +if test "${enable_rust_debug+set}" = set; then : + enableval=$enable_rust_debug; rust_debug_release=$enableval +else + rust_debug_release=release +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Rust code with debugging information" >&5 +$as_echo_n "checking whether to build Rust code with debugging information... " >&6; } + if test "x$rust_debug_release" = "xyes" ; then + rust_debug_release=debug + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + RUST_TARGET_SUBDIR=${rust_debug_release} + + +fi + if test "x$rust_debug_release" = "xdebug"; then + RUST_DEBUG_TRUE= + RUST_DEBUG_FALSE='#' +else + RUST_DEBUG_TRUE='#' + RUST_DEBUG_FALSE= +fi + + if test "$enable_rust" != no; then + ENABLE_RUST_TRUE= + ENABLE_RUST_FALSE='#' +else + ENABLE_RUST_TRUE='#' + ENABLE_RUST_FALSE= +fi + + + +# Check whether --with-libarchive was given. +if test "${with_libarchive+set}" = set; then : + withval=$with_libarchive; : +else + with_libarchive=maybe +fi + + +if test x$with_libarchive != xno ; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LIBARCHIVE_DEPENDENCY" >&5 +$as_echo_n "checking for $LIBARCHIVE_DEPENDENCY... " >&6; } + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LIBARCHIVE_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LIBARCHIVE_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + have_libarchive=yes +else + have_libarchive=no +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_libarchive" >&5 +$as_echo "$have_libarchive" >&6; } + if test x$have_libarchive = xno && test x$with_libarchive != xmaybe ; then : + + as_fn_error $? "libarchive is enabled but could not be found" "$LINENO" 5 + +fi + if test x$have_libarchive = xyes; then : + + +$as_echo "#define HAVE_LIBARCHIVE 1" >>confdefs.h + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_LIBARCHIVE" >&5 +$as_echo_n "checking for OT_DEP_LIBARCHIVE... " >&6; } + +if test -n "$OT_DEP_LIBARCHIVE_CFLAGS"; then + pkg_cv_OT_DEP_LIBARCHIVE_CFLAGS="$OT_DEP_LIBARCHIVE_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LIBARCHIVE_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LIBARCHIVE_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LIBARCHIVE_CFLAGS=`$PKG_CONFIG --cflags "$LIBARCHIVE_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_LIBARCHIVE_LIBS"; then + pkg_cv_OT_DEP_LIBARCHIVE_LIBS="$OT_DEP_LIBARCHIVE_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LIBARCHIVE_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LIBARCHIVE_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LIBARCHIVE_LIBS=`$PKG_CONFIG --libs "$LIBARCHIVE_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_LIBARCHIVE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$LIBARCHIVE_DEPENDENCY" 2>&1` + else + OT_DEP_LIBARCHIVE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$LIBARCHIVE_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_LIBARCHIVE_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($LIBARCHIVE_DEPENDENCY) were not met: + +$OT_DEP_LIBARCHIVE_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_LIBARCHIVE_CFLAGS +and OT_DEP_LIBARCHIVE_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_LIBARCHIVE_CFLAGS +and OT_DEP_LIBARCHIVE_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_LIBARCHIVE_CFLAGS=$pkg_cv_OT_DEP_LIBARCHIVE_CFLAGS + OT_DEP_LIBARCHIVE_LIBS=$pkg_cv_OT_DEP_LIBARCHIVE_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + save_LIBS=$LIBS + LIBS=$OT_DEP_LIBARCHIVE_LIBS + for ac_func in archive_read_support_filter_all +do : + ac_fn_c_check_func "$LINENO" "archive_read_support_filter_all" "ac_cv_func_archive_read_support_filter_all" +if test "x$ac_cv_func_archive_read_support_filter_all" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL 1 +_ACEOF + +fi +done + + LIBS=$save_LIBS + with_libarchive=yes + +else + + with_libarchive=no + +fi + +else + with_libarchive=no +fi +if test x$with_libarchive != xno; then OSTREE_FEATURES="$OSTREE_FEATURES libarchive"; fi + if test $with_libarchive != no; then + USE_LIBARCHIVE_TRUE= + USE_LIBARCHIVE_FALSE='#' +else + USE_LIBARCHIVE_TRUE='#' + USE_LIBARCHIVE_FALSE= +fi + + +SELINUX_DEPENDENCY="libselinux >= 2.1.13" + + +# Check whether --with-selinux was given. +if test "${with_selinux+set}" = set; then : + withval=$with_selinux; : +else + with_selinux=maybe +fi + + +if test x$with_selinux != xno ; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $SELINUX_DEPENDENCY" >&5 +$as_echo_n "checking for $SELINUX_DEPENDENCY... " >&6; } + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$SELINUX_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$SELINUX_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + have_selinux=yes +else + have_selinux=no +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_selinux" >&5 +$as_echo "$have_selinux" >&6; } + if test x$have_selinux = xno && test x$with_selinux != xmaybe ; then : + + as_fn_error $? "SELinux is enabled but could not be found" "$LINENO" 5 + +fi + if test x$have_selinux = xyes; then : + + +$as_echo "#define HAVE_SELINUX 1" >>confdefs.h + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_SELINUX" >&5 +$as_echo_n "checking for OT_DEP_SELINUX... " >&6; } + +if test -n "$OT_DEP_SELINUX_CFLAGS"; then + pkg_cv_OT_DEP_SELINUX_CFLAGS="$OT_DEP_SELINUX_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$SELINUX_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$SELINUX_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_SELINUX_CFLAGS=`$PKG_CONFIG --cflags "$SELINUX_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_SELINUX_LIBS"; then + pkg_cv_OT_DEP_SELINUX_LIBS="$OT_DEP_SELINUX_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$SELINUX_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$SELINUX_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_SELINUX_LIBS=`$PKG_CONFIG --libs "$SELINUX_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_SELINUX_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$SELINUX_DEPENDENCY" 2>&1` + else + OT_DEP_SELINUX_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$SELINUX_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_SELINUX_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($SELINUX_DEPENDENCY) were not met: + +$OT_DEP_SELINUX_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_SELINUX_CFLAGS +and OT_DEP_SELINUX_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_SELINUX_CFLAGS +and OT_DEP_SELINUX_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_SELINUX_CFLAGS=$pkg_cv_OT_DEP_SELINUX_CFLAGS + OT_DEP_SELINUX_LIBS=$pkg_cv_OT_DEP_SELINUX_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + with_selinux=yes + +else + + with_selinux=no + +fi + +else + with_selinux=no +fi +if test x$with_selinux != xno; then OSTREE_FEATURES="$OSTREE_FEATURES selinux"; fi + if test $with_selinux != no; then + USE_SELINUX_TRUE= + USE_SELINUX_FALSE='#' +else + USE_SELINUX_TRUE='#' + USE_SELINUX_FALSE= +fi + + + +# Check whether --with-smack was given. +if test "${with_smack+set}" = set; then : + withval=$with_smack; : +else + with_smack=no +fi + +if test x$with_smack = xyes; then : + + +$as_echo "#define WITH_SMACK 1" >>confdefs.h + + +fi + if test $with_smack != no; then + USE_SMACK_TRUE= + USE_SMACK_FALSE='#' +else + USE_SMACK_TRUE='#' + USE_SMACK_FALSE= +fi + + + +# Check whether --with-crypto was given. +if test "${with_crypto+set}" = set; then : + withval=$with_crypto; : +else + with_crypto=glib +fi + + +if test $with_crypto = glib; then : + +elif test $with_crypto = openssl; then : + with_openssl=yes +elif test $with_crypto = gnutls; then : + +else + as_fn_error $? "Invalid --with-crypto $with_crypto" "$LINENO" 5 + +fi + +OPENSSL_DEPENDENCY="libcrypto >= 1.0.1" + +# Check whether --with-openssl was given. +if test "${with_openssl+set}" = set; then : + withval=$with_openssl; with_openssl=$withval +else + with_openssl=no +fi + +if test x$with_openssl != xno ; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_CRYPTO" >&5 +$as_echo_n "checking for OT_DEP_CRYPTO... " >&6; } + +if test -n "$OT_DEP_CRYPTO_CFLAGS"; then + pkg_cv_OT_DEP_CRYPTO_CFLAGS="$OT_DEP_CRYPTO_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$OPENSSL_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$OPENSSL_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_CRYPTO_CFLAGS=`$PKG_CONFIG --cflags "$OPENSSL_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_CRYPTO_LIBS"; then + pkg_cv_OT_DEP_CRYPTO_LIBS="$OT_DEP_CRYPTO_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$OPENSSL_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$OPENSSL_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_CRYPTO_LIBS=`$PKG_CONFIG --libs "$OPENSSL_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_CRYPTO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$OPENSSL_DEPENDENCY" 2>&1` + else + OT_DEP_CRYPTO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$OPENSSL_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_CRYPTO_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($OPENSSL_DEPENDENCY) were not met: + +$OT_DEP_CRYPTO_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_CRYPTO_CFLAGS +and OT_DEP_CRYPTO_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_CRYPTO_CFLAGS +and OT_DEP_CRYPTO_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_CRYPTO_CFLAGS=$pkg_cv_OT_DEP_CRYPTO_CFLAGS + OT_DEP_CRYPTO_LIBS=$pkg_cv_OT_DEP_CRYPTO_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + +$as_echo "#define HAVE_OPENSSL 1" >>confdefs.h + + with_crypto=openssl + with_openssl=yes + +else + + with_openssl=no + +fi +if test x$with_openssl != xno; then OSTREE_FEATURES="$OSTREE_FEATURES openssl"; fi + if test $with_openssl != no; then + USE_OPENSSL_TRUE= + USE_OPENSSL_FALSE='#' +else + USE_OPENSSL_TRUE='#' + USE_OPENSSL_FALSE= +fi + + +GNUTLS_DEPENDENCY="gnutls >= 3.5.0" +if test $with_crypto = gnutls ; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_CRYPTO" >&5 +$as_echo_n "checking for OT_DEP_CRYPTO... " >&6; } + +if test -n "$OT_DEP_CRYPTO_CFLAGS"; then + pkg_cv_OT_DEP_CRYPTO_CFLAGS="$OT_DEP_CRYPTO_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$GNUTLS_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$GNUTLS_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_CRYPTO_CFLAGS=`$PKG_CONFIG --cflags "$GNUTLS_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_CRYPTO_LIBS"; then + pkg_cv_OT_DEP_CRYPTO_LIBS="$OT_DEP_CRYPTO_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$GNUTLS_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$GNUTLS_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_CRYPTO_LIBS=`$PKG_CONFIG --libs "$GNUTLS_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_CRYPTO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$GNUTLS_DEPENDENCY" 2>&1` + else + OT_DEP_CRYPTO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$GNUTLS_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_CRYPTO_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($GNUTLS_DEPENDENCY) were not met: + +$OT_DEP_CRYPTO_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_CRYPTO_CFLAGS +and OT_DEP_CRYPTO_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_CRYPTO_CFLAGS +and OT_DEP_CRYPTO_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_CRYPTO_CFLAGS=$pkg_cv_OT_DEP_CRYPTO_CFLAGS + OT_DEP_CRYPTO_LIBS=$pkg_cv_OT_DEP_CRYPTO_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + +$as_echo "#define HAVE_GNUTLS 1" >>confdefs.h + + OSTREE_FEATURES="$OSTREE_FEATURES gnutls" + +fi + if test $with_crypto = gnutls; then + USE_GNUTLS_TRUE= + USE_GNUTLS_FALSE='#' +else + USE_GNUTLS_TRUE='#' + USE_GNUTLS_FALSE= +fi + + +AVAHI_DEPENDENCY="avahi-client >= 0.6.31 avahi-glib >= 0.6.31" + + +# Check whether --with-avahi was given. +if test "${with_avahi+set}" = set; then : + withval=$with_avahi; : +else + with_avahi=maybe +fi + + +if test x$with_avahi != xno ; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $AVAHI_DEPENDENCY" >&5 +$as_echo_n "checking for $AVAHI_DEPENDENCY... " >&6; } + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$AVAHI_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$AVAHI_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + have_avahi=yes +else + have_avahi=no +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_avahi" >&5 +$as_echo "$have_avahi" >&6; } + if test x$have_avahi = xno && test x$with_avahi != xmaybe ; then : + + as_fn_error $? "Avahi is enabled but could not be found" "$LINENO" 5 + +fi + if test x$have_avahi = xyes; then : + + +$as_echo "#define HAVE_AVAHI 1" >>confdefs.h + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_AVAHI" >&5 +$as_echo_n "checking for OT_DEP_AVAHI... " >&6; } + +if test -n "$OT_DEP_AVAHI_CFLAGS"; then + pkg_cv_OT_DEP_AVAHI_CFLAGS="$OT_DEP_AVAHI_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$AVAHI_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$AVAHI_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_AVAHI_CFLAGS=`$PKG_CONFIG --cflags "$AVAHI_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_AVAHI_LIBS"; then + pkg_cv_OT_DEP_AVAHI_LIBS="$OT_DEP_AVAHI_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$AVAHI_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$AVAHI_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_AVAHI_LIBS=`$PKG_CONFIG --libs "$AVAHI_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_AVAHI_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$AVAHI_DEPENDENCY" 2>&1` + else + OT_DEP_AVAHI_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$AVAHI_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_AVAHI_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($AVAHI_DEPENDENCY) were not met: + +$OT_DEP_AVAHI_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_AVAHI_CFLAGS +and OT_DEP_AVAHI_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_AVAHI_CFLAGS +and OT_DEP_AVAHI_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_AVAHI_CFLAGS=$pkg_cv_OT_DEP_AVAHI_CFLAGS + OT_DEP_AVAHI_LIBS=$pkg_cv_OT_DEP_AVAHI_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + with_avahi=yes + +else + + with_avahi=no + +fi + +else + with_avahi=no +fi +if test x$with_avahi != xno; then OSTREE_FEATURES="$OSTREE_FEATURES avahi"; fi + if test $with_avahi != no; then + USE_AVAHI_TRUE= + USE_AVAHI_FALSE='#' +else + USE_AVAHI_TRUE='#' + USE_AVAHI_FALSE= +fi + + +LIBMOUNT_DEPENDENCY="mount >= 2.23.0" + + +# Check whether --with-libmount was given. +if test "${with_libmount+set}" = set; then : + withval=$with_libmount; : +else + with_libmount=maybe +fi + + +if test x$with_libmount != xno ; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LIBMOUNT_DEPENDENCY" >&5 +$as_echo_n "checking for $LIBMOUNT_DEPENDENCY... " >&6; } + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LIBMOUNT_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LIBMOUNT_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + have_libmount=yes +else + have_libmount=no +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_libmount" >&5 +$as_echo "$have_libmount" >&6; } + if test x$have_libmount = xno && test x$with_libmount != xmaybe ; then : + + as_fn_error $? "libmount is enabled but could not be found" "$LINENO" 5 + +fi + if test x$have_libmount = xyes; then : + + +$as_echo "#define HAVE_LIBMOUNT 1" >>confdefs.h + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OT_DEP_LIBMOUNT" >&5 +$as_echo_n "checking for OT_DEP_LIBMOUNT... " >&6; } + +if test -n "$OT_DEP_LIBMOUNT_CFLAGS"; then + pkg_cv_OT_DEP_LIBMOUNT_CFLAGS="$OT_DEP_LIBMOUNT_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LIBMOUNT_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LIBMOUNT_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LIBMOUNT_CFLAGS=`$PKG_CONFIG --cflags "$LIBMOUNT_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OT_DEP_LIBMOUNT_LIBS"; then + pkg_cv_OT_DEP_LIBMOUNT_LIBS="$OT_DEP_LIBMOUNT_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LIBMOUNT_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$LIBMOUNT_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OT_DEP_LIBMOUNT_LIBS=`$PKG_CONFIG --libs "$LIBMOUNT_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OT_DEP_LIBMOUNT_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$LIBMOUNT_DEPENDENCY" 2>&1` + else + OT_DEP_LIBMOUNT_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$LIBMOUNT_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OT_DEP_LIBMOUNT_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($LIBMOUNT_DEPENDENCY) were not met: + +$OT_DEP_LIBMOUNT_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables OT_DEP_LIBMOUNT_CFLAGS +and OT_DEP_LIBMOUNT_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables OT_DEP_LIBMOUNT_CFLAGS +and OT_DEP_LIBMOUNT_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + OT_DEP_LIBMOUNT_CFLAGS=$pkg_cv_OT_DEP_LIBMOUNT_CFLAGS + OT_DEP_LIBMOUNT_LIBS=$pkg_cv_OT_DEP_LIBMOUNT_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + with_libmount=yes + save_LIBS=$LIBS + LIBS=$OT_DEP_LIBMOUNT_LIBS + for ac_func in mnt_unref_cache +do : + ac_fn_c_check_func "$LINENO" "mnt_unref_cache" "ac_cv_func_mnt_unref_cache" +if test "x$ac_cv_func_mnt_unref_cache" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MNT_UNREF_CACHE 1 +_ACEOF + +fi +done + + LIBS=$save_LIBS + +else + + with_libmount=no + +fi + +else + with_libmount=no +fi +if test x$with_libmount != xno; then OSTREE_FEATURES="$OSTREE_FEATURES libmount"; fi + if test $with_libmount != no; then + USE_LIBMOUNT_TRUE= + USE_LIBMOUNT_FALSE='#' +else + USE_LIBMOUNT_TRUE='#' + USE_LIBMOUNT_FALSE= +fi + + +# Enabled by default because I think people should use it. +# Check whether --enable-rofiles-fuse was given. +if test "${enable_rofiles_fuse+set}" = set; then : + enableval=$enable_rofiles_fuse; +else + enable_rofiles_fuse=yes +fi + +if test x$enable_rofiles_fuse != xno ; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BUILDOPT_FUSE" >&5 +$as_echo_n "checking for BUILDOPT_FUSE... " >&6; } + +if test -n "$BUILDOPT_FUSE_CFLAGS"; then + pkg_cv_BUILDOPT_FUSE_CFLAGS="$BUILDOPT_FUSE_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$FUSE_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$FUSE_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_BUILDOPT_FUSE_CFLAGS=`$PKG_CONFIG --cflags "$FUSE_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$BUILDOPT_FUSE_LIBS"; then + pkg_cv_BUILDOPT_FUSE_LIBS="$BUILDOPT_FUSE_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$FUSE_DEPENDENCY\""; } >&5 + ($PKG_CONFIG --exists --print-errors "$FUSE_DEPENDENCY") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_BUILDOPT_FUSE_LIBS=`$PKG_CONFIG --libs "$FUSE_DEPENDENCY" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + BUILDOPT_FUSE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$FUSE_DEPENDENCY" 2>&1` + else + BUILDOPT_FUSE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$FUSE_DEPENDENCY" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$BUILDOPT_FUSE_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements ($FUSE_DEPENDENCY) were not met: + +$BUILDOPT_FUSE_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables BUILDOPT_FUSE_CFLAGS +and BUILDOPT_FUSE_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables BUILDOPT_FUSE_CFLAGS +and BUILDOPT_FUSE_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + BUILDOPT_FUSE_CFLAGS=$pkg_cv_BUILDOPT_FUSE_CFLAGS + BUILDOPT_FUSE_LIBS=$pkg_cv_BUILDOPT_FUSE_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + +else + enable_rofiles_fuse=no +fi + if test x$enable_rofiles_fuse = xyes; then + BUILDOPT_FUSE_TRUE= + BUILDOPT_FUSE_FALSE='#' +else + BUILDOPT_FUSE_TRUE='#' + BUILDOPT_FUSE_FALSE= +fi + + + +# Check whether --with-dracut was given. +if test "${with_dracut+set}" = set; then : + withval=$with_dracut; +else + with_dracut=no +fi + +case x$with_dracut in + xno) ;; + xyes) ;; + xyesbutnoconf) ;; + *) as_fn_error $? "Unknown --with-dracut value $with_dracut" "$LINENO" 5 +esac + if test x$with_dracut = xyes || test x$with_dracut = xyesbutnoconf; then + BUILDOPT_DRACUT_TRUE= + BUILDOPT_DRACUT_FALSE='#' +else + BUILDOPT_DRACUT_TRUE='#' + BUILDOPT_DRACUT_FALSE= +fi + + if test x$with_dracut = xyes; then + BUILDOPT_DRACUT_CONF_TRUE= + BUILDOPT_DRACUT_CONF_FALSE='#' +else + BUILDOPT_DRACUT_CONF_TRUE='#' + BUILDOPT_DRACUT_CONF_FALSE= +fi + + + +# Check whether --with-mkinitcpio was given. +if test "${with_mkinitcpio+set}" = set; then : + withval=$with_mkinitcpio; +else + with_mkinitcpio=no +fi + + if test x$with_mkinitcpio = xyes; then + BUILDOPT_MKINITCPIO_TRUE= + BUILDOPT_MKINITCPIO_FALSE='#' +else + BUILDOPT_MKINITCPIO_TRUE='#' + BUILDOPT_MKINITCPIO_FALSE= +fi + + + +# Check whether --with-libsystemd was given. +if test "${with_libsystemd+set}" = set; then : + withval=$with_libsystemd; : +else + with_libsystemd=maybe +fi + + +if test x$with_libsystemd != xno ; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libsystemd" >&5 +$as_echo_n "checking for libsystemd... " >&6; } + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + have_libsystemd=yes +else + have_libsystemd=no +fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_libsystemd" >&5 +$as_echo "$have_libsystemd" >&6; } + if test x$have_libsystemd = xno && test x$with_libsystemd != xmaybe ; then : + + as_fn_error $? "libsystemd is enabled but could not be found" "$LINENO" 5 + +fi + if test x$have_libsystemd = xyes; then : + + +$as_echo "#define HAVE_LIBSYSTEMD 1" >>confdefs.h + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSYSTEMD" >&5 +$as_echo_n "checking for LIBSYSTEMD... " >&6; } + +if test -n "$LIBSYSTEMD_CFLAGS"; then + pkg_cv_LIBSYSTEMD_CFLAGS="$LIBSYSTEMD_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBSYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "libsystemd" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$LIBSYSTEMD_LIBS"; then + pkg_cv_LIBSYSTEMD_LIBS="$LIBSYSTEMD_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_LIBSYSTEMD_LIBS=`$PKG_CONFIG --libs "libsystemd" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + LIBSYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsystemd" 2>&1` + else + LIBSYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsystemd" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$LIBSYSTEMD_PKG_ERRORS" >&5 + + as_fn_error $? "Package requirements (libsystemd) were not met: + +$LIBSYSTEMD_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables LIBSYSTEMD_CFLAGS +and LIBSYSTEMD_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details." "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables LIBSYSTEMD_CFLAGS +and LIBSYSTEMD_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see . +See \`config.log' for more details" "$LINENO" 5; } +else + LIBSYSTEMD_CFLAGS=$pkg_cv_LIBSYSTEMD_CFLAGS + LIBSYSTEMD_LIBS=$pkg_cv_LIBSYSTEMD_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +fi + with_libsystemd=yes + +else + + with_libsystemd=no + +fi + +else + with_libsystemd=no +fi + +if test "x$with_libsystemd" = "xyes"; then : + + +# Check whether --with-systemdsystemunitdir was given. +if test "${with_systemdsystemunitdir+set}" = set; then : + withval=$with_systemdsystemunitdir; +else + with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) +fi + + if test "x$with_systemdsystemunitdir" != "xno"; then : + + systemdsystemunitdir=$with_systemdsystemunitdir + + +fi + +# Check whether --with-systemdsystemgeneratordir was given. +if test "${with_systemdsystemgeneratordir+set}" = set; then : + withval=$with_systemdsystemgeneratordir; +else + with_systemdsystemgeneratordir=$($PKG_CONFIG --variable=systemdsystemgeneratordir systemd) +fi + + if test "x$with_systemdsystemgeneratordir" != "xno"; then : + + systemdsystemgeneratordir=$with_systemdsystemgeneratordir + + +fi + +fi + if test x$with_libsystemd = xyes; then + BUILDOPT_SYSTEMD_TRUE= + BUILDOPT_SYSTEMD_FALSE='#' +else + BUILDOPT_SYSTEMD_TRUE='#' + BUILDOPT_SYSTEMD_FALSE= +fi + + if test x$with_libsystemd = xyes && test x$with_libmount = xyes; then + BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE= + BUILDOPT_SYSTEMD_AND_LIBMOUNT_FALSE='#' +else + BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE='#' + BUILDOPT_SYSTEMD_AND_LIBMOUNT_FALSE= +fi + +if test -z "$BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE"; then : + +$as_echo "#define BUILDOPT_LIBSYSTEMD_AND_LIBMOUNT 1" >>confdefs.h + +fi +if test x$with_libsystemd = xyes; then OSTREE_FEATURES="$OSTREE_FEATURES systemd"; fi + + +# Check whether --with-builtin-grub2-mkconfig was given. +if test "${with_builtin_grub2_mkconfig+set}" = set; then : + withval=$with_builtin_grub2_mkconfig; +else + with_builtin_grub2_mkconfig=no +fi + + if test x$with_builtin_grub2_mkconfig = xyes; then + BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE= + BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE='#' +else + BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE='#' + BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE= +fi + +if test -z "$BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE"; then : + +$as_echo "#define USE_BUILTIN_GRUB2_MKCONFIG 1" >>confdefs.h + +fi + +# Check whether --with-grub2-mkconfig-path was given. +if test "${with_grub2_mkconfig_path+set}" = set; then : + withval=$with_grub2_mkconfig_path; +fi + +if test x$with_grub2_mkconfig_path = x; then : + + for ac_prog in grub2-mkconfig grub-mkconfig +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_GRUB2_MKCONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$GRUB2_MKCONFIG"; then + ac_cv_prog_GRUB2_MKCONFIG="$GRUB2_MKCONFIG" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_GRUB2_MKCONFIG="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +GRUB2_MKCONFIG=$ac_cv_prog_GRUB2_MKCONFIG +if test -n "$GRUB2_MKCONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GRUB2_MKCONFIG" >&5 +$as_echo "$GRUB2_MKCONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$GRUB2_MKCONFIG" && break +done +test -n "$GRUB2_MKCONFIG" || GRUB2_MKCONFIG="grub2-mkconfig" + + +else + GRUB2_MKCONFIG=$with_grub2_mkconfig_path +fi + +cat >>confdefs.h <<_ACEOF +#define GRUB2_MKCONFIG_PATH "$GRUB2_MKCONFIG" +_ACEOF + + + +# Check whether --with-static-compiler was given. +if test "${with_static_compiler+set}" = set; then : + withval=$with_static_compiler; +else + with_static_compiler=no +fi + + if test "x$with_static_compiler" != xno; then + BUILDOPT_USE_STATIC_COMPILER_TRUE= + BUILDOPT_USE_STATIC_COMPILER_FALSE='#' +else + BUILDOPT_USE_STATIC_COMPILER_TRUE='#' + BUILDOPT_USE_STATIC_COMPILER_FALSE= +fi + +STATIC_COMPILER=$with_static_compiler + + +if test "x$found_introspection" = xyes && test x$using_asan != xyes; then : + + # Extract the first word of "gjs", so it can be a program name with args. +set dummy gjs; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GJS+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GJS in + [\\/]* | ?:[\\/]*) + ac_cv_path_GJS="$GJS" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GJS="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +GJS=$ac_cv_path_GJS +if test -n "$GJS"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GJS" >&5 +$as_echo "$GJS" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -n "$GJS"; then + have_gjs=yes + else + have_gjs=no + fi + +else + have_gjs=no +fi + if test x$have_gjs = xyes; then + BUILDOPT_GJS_TRUE= + BUILDOPT_GJS_FALSE='#' +else + BUILDOPT_GJS_TRUE='#' + BUILDOPT_GJS_FALSE= +fi + + +# Do we enable building experimental (non-stable) API? +# The OSTREE_ENABLE_EXPERIMENTAL_API #define is used internally and in public +# headers, so any consumer of libostree who wants to use experimental API must +# #define OSTREE_ENABLE_EXPERIMENTAL_API 1 +# before including libostree headers. This means the name in the AC_DEFINE below +# is public API. +# Check whether --enable-experimental-api was given. +if test "${enable_experimental_api+set}" = set; then : + enableval=$enable_experimental_api; +else + enable_experimental_api=no +fi + +if test x$enable_experimental_api = xyes; then : + +$as_echo "#define OSTREE_ENABLE_EXPERIMENTAL_API 1" >>confdefs.h + + OSTREE_FEATURES="$OSTREE_FEATURES experimental" + +fi + if test x$enable_experimental_api = xyes; then + ENABLE_EXPERIMENTAL_API_TRUE= + ENABLE_EXPERIMENTAL_API_FALSE='#' +else + ENABLE_EXPERIMENTAL_API_TRUE='#' + ENABLE_EXPERIMENTAL_API_FALSE= +fi + + if test x$is_release_build != xyes; then + BUILDOPT_IS_DEVEL_BUILD_TRUE= + BUILDOPT_IS_DEVEL_BUILD_FALSE='#' +else + BUILDOPT_IS_DEVEL_BUILD_TRUE='#' + BUILDOPT_IS_DEVEL_BUILD_FALSE= +fi + +if test -z "$BUILDOPT_IS_DEVEL_BUILD_TRUE"; then : + +$as_echo "#define BUILDOPT_IS_DEVEL_BUILD 1" >>confdefs.h + + release_build_type=devel +else + release_build_type=release +fi +OSTREE_FEATURES="$OSTREE_FEATURES $release_build_type" + +# P2P API is public in OSTree >= 2018.6 +OSTREE_FEATURES="$OSTREE_FEATURES p2p" + +# Strip leading whitespace +OSTREE_FEATURES=$(echo ${OSTREE_FEATURES}) + +ac_config_files="$ac_config_files Makefile apidoc/Makefile src/libostree/ostree-1.pc src/libostree/ostree-version.h" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +$as_echo_n "checking that generated files are newer than configure... " >&6; } + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 +$as_echo "done" >&6; } + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_ASAN_TRUE}" && test -z "${BUILDOPT_ASAN_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_ASAN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_TSAN_TRUE}" && test -z "${BUILDOPT_TSAN_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_TSAN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_INSTALLED_TESTS_TRUE}" && test -z "${ENABLE_INSTALLED_TESTS_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_INSTALLED_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE}" && test -z "${ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_INSTALLED_TESTS_EXCLUSIVE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_ALWAYS_BUILD_TESTS_TRUE}" && test -z "${ENABLE_ALWAYS_BUILD_TESTS_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_ALWAYS_BUILD_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_CURL_TRUE}" && test -z "${USE_CURL_FALSE}"; then + as_fn_error $? "conditional \"USE_CURL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_LIBSOUP_TRUE}" && test -z "${USE_LIBSOUP_FALSE}"; then + as_fn_error $? "conditional \"USE_LIBSOUP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_LIBSOUP_CLIENT_CERTS_TRUE}" && test -z "${HAVE_LIBSOUP_CLIENT_CERTS_FALSE}"; then + as_fn_error $? "conditional \"HAVE_LIBSOUP_CLIENT_CERTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_CURL_OR_SOUP_TRUE}" && test -z "${USE_CURL_OR_SOUP_FALSE}"; then + as_fn_error $? "conditional \"USE_CURL_OR_SOUP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_INTROSPECTION_TRUE}" && test -z "${HAVE_INTROSPECTION_FALSE}"; then + as_fn_error $? "conditional \"HAVE_INTROSPECTION\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_INTROSPECTION_TRUE}" && test -z "${BUILDOPT_INTROSPECTION_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_INTROSPECTION\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_GPGME_TRUE}" && test -z "${USE_GPGME_FALSE}"; then + as_fn_error $? "conditional \"USE_GPGME\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_LIBSODIUM_TRUE}" && test -z "${USE_LIBSODIUM_FALSE}"; then + as_fn_error $? "conditional \"USE_LIBSODIUM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_GTK_DOC_TRUE}" && test -z "${HAVE_GTK_DOC_FALSE}"; then + as_fn_error $? "conditional \"HAVE_GTK_DOC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_GTK_DOC_TRUE}" && test -z "${ENABLE_GTK_DOC_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_GTK_DOC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GTK_DOC_BUILD_HTML_TRUE}" && test -z "${GTK_DOC_BUILD_HTML_FALSE}"; then + as_fn_error $? "conditional \"GTK_DOC_BUILD_HTML\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GTK_DOC_BUILD_PDF_TRUE}" && test -z "${GTK_DOC_BUILD_PDF_FALSE}"; then + as_fn_error $? "conditional \"GTK_DOC_BUILD_PDF\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GTK_DOC_USE_LIBTOOL_TRUE}" && test -z "${GTK_DOC_USE_LIBTOOL_FALSE}"; then + as_fn_error $? "conditional \"GTK_DOC_USE_LIBTOOL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GTK_DOC_USE_REBASE_TRUE}" && test -z "${GTK_DOC_USE_REBASE_FALSE}"; then + as_fn_error $? "conditional \"GTK_DOC_USE_REBASE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_MAN_TRUE}" && test -z "${ENABLE_MAN_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_MAN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${RUST_DEBUG_TRUE}" && test -z "${RUST_DEBUG_FALSE}"; then + as_fn_error $? "conditional \"RUST_DEBUG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_RUST_TRUE}" && test -z "${ENABLE_RUST_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_RUST\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_LIBARCHIVE_TRUE}" && test -z "${USE_LIBARCHIVE_FALSE}"; then + as_fn_error $? "conditional \"USE_LIBARCHIVE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_SELINUX_TRUE}" && test -z "${USE_SELINUX_FALSE}"; then + as_fn_error $? "conditional \"USE_SELINUX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_SMACK_TRUE}" && test -z "${USE_SMACK_FALSE}"; then + as_fn_error $? "conditional \"USE_SMACK\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_OPENSSL_TRUE}" && test -z "${USE_OPENSSL_FALSE}"; then + as_fn_error $? "conditional \"USE_OPENSSL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_GNUTLS_TRUE}" && test -z "${USE_GNUTLS_FALSE}"; then + as_fn_error $? "conditional \"USE_GNUTLS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_AVAHI_TRUE}" && test -z "${USE_AVAHI_FALSE}"; then + as_fn_error $? "conditional \"USE_AVAHI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_LIBMOUNT_TRUE}" && test -z "${USE_LIBMOUNT_FALSE}"; then + as_fn_error $? "conditional \"USE_LIBMOUNT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_FUSE_TRUE}" && test -z "${BUILDOPT_FUSE_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_FUSE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_DRACUT_TRUE}" && test -z "${BUILDOPT_DRACUT_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_DRACUT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_DRACUT_CONF_TRUE}" && test -z "${BUILDOPT_DRACUT_CONF_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_DRACUT_CONF\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_MKINITCPIO_TRUE}" && test -z "${BUILDOPT_MKINITCPIO_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_MKINITCPIO\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_SYSTEMD_TRUE}" && test -z "${BUILDOPT_SYSTEMD_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_SYSTEMD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE}" && test -z "${BUILDOPT_SYSTEMD_AND_LIBMOUNT_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_SYSTEMD_AND_LIBMOUNT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE}" && test -z "${BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_BUILTIN_GRUB2_MKCONFIG\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_USE_STATIC_COMPILER_TRUE}" && test -z "${BUILDOPT_USE_STATIC_COMPILER_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_USE_STATIC_COMPILER\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_GJS_TRUE}" && test -z "${BUILDOPT_GJS_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_GJS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_EXPERIMENTAL_API_TRUE}" && test -z "${ENABLE_EXPERIMENTAL_API_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_EXPERIMENTAL_API\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILDOPT_IS_DEVEL_BUILD_TRUE}" && test -z "${BUILDOPT_IS_DEVEL_BUILD_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_IS_DEVEL_BUILD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by libostree $as_me 2020.4, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +libostree config.status 2020.4 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' +configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_import \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_cv_nm_interface \ +nm_file_list_spec \ +lt_cv_truncate_bin \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +configure_time_dlsearch_path \ +configure_time_lt_sys_library_path; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' + +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile' + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "apidoc/Makefile") CONFIG_FILES="$CONFIG_FILES apidoc/Makefile" ;; + "src/libostree/ostree-1.pc") CONFIG_FILES="$CONFIG_FILES src/libostree/ostree-1.pc" ;; + "src/libostree/ostree-version.h") CONFIG_FILES="$CONFIG_FILES src/libostree/ostree-version.h" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + case $CONFIG_FILES in #( + *\'*) : + eval set x "$CONFIG_FILES" ;; #( + *) : + set x $CONFIG_FILES ;; #( + *) : + ;; +esac + shift + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf + do + # Strip MF so we end up with the name of the file. + am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`$as_dirname -- "$am_mf" || +$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$am_mf" : 'X\(//\)[^/]' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$am_mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + am_filepart=`$as_basename -- "$am_mf" || +$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$am_mf" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { echo "$as_me:$LINENO: cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles" >&5 + (cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } || am_rc=$? + done + if test $am_rc -ne 0; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. Try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking). +See \`config.log' for more details" "$LINENO" 5; } + fi + { am_dirpart=; unset am_dirpart;} + { am_filepart=; unset am_filepart;} + { am_mf=; unset am_mf;} + { am_rc=; unset am_rc;} + rm -f conftest-deps.mk +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +# Copyright (C) 2014 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 . + + +# The names of the tagged configurations supported by this script. +available_tags='' + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shared archive member basename,for filename based shared library versioning on AIX. +shared_archive_member_spec=$shared_archive_member_spec + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm into a list of symbols to manually relocate. +global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name lister interface. +nm_interface=$lt_lt_cv_nm_interface + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and where our libraries should be installed. +lt_sysroot=$lt_sysroot + +# Command to truncate a binary pipe. +lt_truncate_bin=$lt_lt_cv_truncate_bin + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Detected run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path + +# Explicit LT_SYS_LIBRARY_PATH set during ./configure time. +configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \$shlibpath_var if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x$2 in + x) + ;; + *:) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" + ;; + x:*) + eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" + ;; + *) + eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" + ;; + esac +} + + +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in $*""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} + + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain=$ac_aux_dir/ltmain.sh + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +echo " + libostree $VERSION ($release_build_type) + features: $OSTREE_FEATURES + =============== + + + introspection: $found_introspection + Rust (internal oxidation): $rust_debug_release + rofiles-fuse: $enable_rofiles_fuse + HTTP backend: $fetcher_backend + \"ostree trivial-httpd\": $enable_trivial_httpd_cmdline + SELinux: $with_selinux + fs-verity: $ac_cv_header_linux_fsverity_h + cryptographic checksums: $with_crypto + systemd: $with_libsystemd + libmount: $with_libmount + libsodium (ed25519 signatures): $with_ed25519_libsodium + libarchive (parse tar files directly): $with_libarchive + static deltas: yes (always enabled now) + O_TMPFILE: $enable_otmpfile + wrpseudo-compat: $enable_wrpseudo_compat + man pages (xsltproc): $enable_man + api docs (gtk-doc): $enable_gtk_doc + installed tests: $enable_installed_tests + gjs-based tests: $have_gjs + dracut: $with_dracut + mkinitcpio: $with_mkinitcpio + Static compiler for ostree-prepare-root: $with_static_compiler + Experimental API $enable_experimental_api" +if test x$with_builtin_grub2_mkconfig = xyes; then : + + echo " builtin grub2-mkconfig (instead of system): $with_builtin_grub2_mkconfig" + +else + + echo " grub2-mkconfig path: $GRUB2_MKCONFIG" + +fi +echo "" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..855528c --- /dev/null +++ b/configure.ac @@ -0,0 +1,662 @@ +AC_PREREQ([2.63]) +dnl To do a release: follow the instructions to update libostree-released.sym from +dnl libostree-devel.sym, update the checksum in test-symbols.sh, set is_release_build=yes +dnl below. Then make another post-release commit to bump the version and set +dnl is_release_build=no. +dnl Seed the release notes with `git-shortlog-with-prs ..`. Then use +dnl `git-evtag` to create the tag and push it. Finally, create a GitHub release and attach +dnl the tarball from `make dist`. +m4_define([year_version], [2020]) +m4_define([release_version], [4]) +m4_define([package_version], [year_version.release_version]) +AC_INIT([libostree], [package_version], [walters@verbum.org]) +is_release_build=yes +AC_CONFIG_HEADER([config.h]) +AC_CONFIG_MACRO_DIR([buildutil]) +AC_CONFIG_AUX_DIR([build-aux]) + +AM_INIT_AUTOMAKE([1.13 -Wno-portability foreign no-define tar-ustar no-dist-gzip dist-xz + color-tests subdir-objects]) +AM_MAINTAINER_MODE([enable]) +AM_SILENT_RULES([yes]) +AC_USE_SYSTEM_EXTENSIONS +AC_SYS_LARGEFILE + +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_YACC + +dnl Versioning information +AC_SUBST([YEAR_VERSION], [year_version]) +AC_SUBST([RELEASE_VERSION], [release_version]) +AC_SUBST([PACKAGE_VERSION], [package_version]) + +AS_IF([echo "$CFLAGS" | grep -q -E -e '-Werror($| )'], [], [ +CC_CHECK_FLAGS_APPEND([WARN_CFLAGS], [CFLAGS], [\ + -pipe \ + -Wall \ + -Werror=empty-body \ + -Werror=strict-prototypes \ + -Werror=missing-prototypes \ + -Werror=implicit-function-declaration \ + "-Werror=format=2 -Werror=format-security -Werror=format-nonliteral" \ + -Werror=pointer-arith -Werror=init-self \ + -Werror=missing-declarations \ + -Werror=return-type \ + -Werror=switch \ + -Werror=overflow \ + -Werror=int-conversion \ + -Werror=parentheses \ + -Werror=undef \ + -Werror=incompatible-pointer-types \ + -Werror=misleading-indentation \ + -Werror=missing-include-dirs -Werror=aggregate-return \ + -Wstrict-aliasing=2 \ + -Werror=unused-result \ +])]) +AC_SUBST(WARN_CFLAGS) + +AC_MSG_CHECKING([for -fsanitize=address in CFLAGS]) +if echo $CFLAGS | grep -q -e -fsanitize=address; then + AC_MSG_RESULT([yes]) + using_asan=yes +else + AC_MSG_RESULT([no]) +fi +AM_CONDITIONAL(BUILDOPT_ASAN, [test x$using_asan = xyes]) +AM_COND_IF([BUILDOPT_ASAN], + [AC_DEFINE([BUILDOPT_ASAN], 1, [Define if we are building with -fsanitize=address])]) + +AC_MSG_CHECKING([for -fsanitize=thread in CFLAGS]) +if echo $CFLAGS | grep -q -e -fsanitize=thread; then + AC_MSG_RESULT([yes]) + using_tsan=yes +else + AC_MSG_RESULT([no]) +fi +AM_CONDITIONAL(BUILDOPT_TSAN, [test x$using_tsan = xyes]) +AM_COND_IF([BUILDOPT_TSAN], + [AC_DEFINE([BUILDOPT_TSAN], 1, [Define if we are building with -fsanitize=thread])]) + +# Initialize libtool +LT_PREREQ([2.2.4]) +LT_INIT([disable-static]) + +OSTREE_FEATURES="" +AC_SUBST([OSTREE_FEATURES]) + +GLIB_TESTS +LIBGLNX_CONFIGURE + +dnl These bits attempt to mirror https://github.com/coreutils/gnulib/blob/e369b04cca4da1534c98628b8ee4648bfca2bb3a/m4/parse-datetime.m4#L27 +AC_CHECK_FUNCS([nanotime clock_gettime]) +AC_STRUCT_TIMEZONE +AC_CHECK_HEADER([sys/xattr.h],,[AC_MSG_ERROR([You must have sys/xattr.h from glibc])]) + +AS_IF([test "$YACC" != "bison -y"], [AC_MSG_ERROR([bison not found but required])]) + +PKG_PROG_PKG_CONFIG + +# PKG_CHECK_VAR added to pkg-config 0.28 +m4_define_default( + [PKG_CHECK_VAR], + [AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config]) + AS_IF([test -z "$$1"], [$1=`$PKG_CONFIG --variable="$3" "$2"`]) + AS_IF([test -n "$$1"], [$4], [$5])]) + +PKG_CHECK_VAR(BASH_COMPLETIONSDIR, [bash-completion], [completionsdir], , + BASH_COMPLETIONSDIR="${datadir}/bash-completion/completions") +AC_SUBST(BASH_COMPLETIONSDIR) + +AM_PATH_GLIB_2_0(,,AC_MSG_ERROR([GLib not found])) + +dnl When bumping the gio-unix-2.0 dependency (or glib-2.0 in general), +dnl remember to bump GLIB_VERSION_MIN_REQUIRED and +dnl GLIB_VERSION_MAX_ALLOWED in Makefile.am +GIO_DEPENDENCY="gio-unix-2.0 >= 2.40.0" +PKG_CHECK_MODULES(OT_DEP_GIO_UNIX, $GIO_DEPENDENCY) + +dnl 5.1.0 is an arbitrary version here +PKG_CHECK_MODULES(OT_DEP_LZMA, liblzma >= 5.0.5) + +dnl Needed for rollsum +PKG_CHECK_MODULES(OT_DEP_ZLIB, zlib) + +dnl We're not actually linking to this, just using the header +PKG_CHECK_MODULES(OT_DEP_E2P, e2p) + +dnl Arbitrary version that's in CentOS7.2 now +CURL_DEPENDENCY=7.29.0 +AC_ARG_WITH(curl, + AS_HELP_STRING([--with-curl], [Use libcurl @<:@default=no@:>@]), + [], [with_curl=no]) +AS_IF([test x$with_curl != xno ], [ + PKG_CHECK_MODULES(OT_DEP_CURL, libcurl >= $CURL_DEPENDENCY) + with_curl=yes + AC_DEFINE([HAVE_LIBCURL], 1, [Define if we have libcurl.pc]) + dnl Currently using libcurl requires soup for trivial-httpd for tests + with_soup_default=yes +], [with_soup_default=check]) +AM_CONDITIONAL(USE_CURL, test x$with_curl != xno) +if test x$with_curl = xyes; then OSTREE_FEATURES="$OSTREE_FEATURES libcurl"; fi +AC_ARG_ENABLE(http2, +AS_HELP_STRING([--disable-http2], + [Disable use of http2 (default: no)]),, + [enable_http2=yes]) +AS_IF([test x$enable_http2 != xno ], [ + AC_DEFINE([BUILDOPT_HTTP2], 1, [Define if we enable http2 by default]) +], [ + OSTREE_FEATURES="$OSTREE_FEATURES no-http2" +]) + +dnl When bumping the libsoup-2.4 dependency, remember to bump +dnl SOUP_VERSION_MIN_REQUIRED and SOUP_VERSION_MAX_ALLOWED in +dnl Makefile.am +SOUP_DEPENDENCY="libsoup-2.4 >= 2.39.1" +AC_ARG_WITH(soup, + AS_HELP_STRING([--with-soup], [Use libsoup @<:@default=yes@:>@]), + [], [with_soup=$with_soup_default]) +AS_IF([test x$with_soup != xno], [ + AC_ARG_ENABLE(libsoup_client_certs, + AS_HELP_STRING([--enable-libsoup-client-certs], + [Require availability of new enough libsoup TLS client cert API (default: auto)]),, + [enable_libsoup_client_certs=auto]) + AC_MSG_CHECKING([for $SOUP_DEPENDENCY]) + PKG_CHECK_EXISTS($SOUP_DEPENDENCY, have_soup=yes, have_soup=no) + AC_MSG_RESULT([$have_soup]) + AS_IF([ test x$have_soup = xno && test x$with_soup != xcheck], [ + AC_MSG_ERROR([libsoup is enabled but could not be found]) + ]) + AS_IF([test x$have_soup = xyes], [ + PKG_CHECK_MODULES(OT_DEP_SOUP, $SOUP_DEPENDENCY) + AC_DEFINE([HAVE_LIBSOUP], 1, [Define if we have libsoup.pc]) + with_soup=yes + save_CFLAGS=$CFLAGS + CFLAGS=$OT_DEP_SOUP_CFLAGS + have_libsoup_client_certs=no + AC_CHECK_DECL([SOUP_SESSION_TLS_INTERACTION], [ + AC_DEFINE([HAVE_LIBSOUP_CLIENT_CERTS], 1, [Define if we have libsoup client certs]) + have_libsoup_client_certs=yes + ], [], [#include ]) + AS_IF([test x$enable_libsoup_client_certs = xyes && test x$have_libsoup_client_certs != xyes], [ + AC_MSG_ERROR([libsoup client certs explicitly requested but not found]) + ]) + CFLAGS=$save_CFLAGS + ], [ + with_soup=no + ]) +], [ with_soup=no ]) +if test x$with_soup != xno; then OSTREE_FEATURES="$OSTREE_FEATURES libsoup"; fi +AM_CONDITIONAL(USE_LIBSOUP, test x$with_soup != xno) +AM_CONDITIONAL(HAVE_LIBSOUP_CLIENT_CERTS, test x$have_libsoup_client_certs = xyes) + +AC_ARG_ENABLE(trivial-httpd-cmdline, + [AS_HELP_STRING([--enable-trivial-httpd-cmdline], + [Continue to support "ostree trivial-httpd" [default=no]])],, + enable_trivial_httpd_cmdline=no) +AS_IF([test x$enable_trivial_httpd_cmdline = xyes], + [AC_DEFINE([BUILDOPT_ENABLE_TRIVIAL_HTTPD_CMDLINE], 1, [Define if we are enabling ostree trivial-httpd entrypoint])] +) + +AS_IF([test x$with_curl = xyes && test x$with_soup = xno], [ + AC_MSG_WARN([Curl enabled, but libsoup is not; libsoup is needed for tests (make check, etc.)]) +]) +AM_CONDITIONAL(USE_CURL_OR_SOUP, test x$with_curl != xno || test x$with_soup != xno) +AS_IF([test x$with_curl != xno || test x$with_soup != xno], + [AC_DEFINE([HAVE_LIBCURL_OR_LIBSOUP], 1, [Define if we have soup or curl])]) +AS_IF([test x$with_curl = xyes], [fetcher_backend=curl], [test x$with_soup = xyes], [fetcher_backend=libsoup], [fetcher_backend=none]) + +m4_ifdef([GOBJECT_INTROSPECTION_CHECK], [ + GOBJECT_INTROSPECTION_CHECK([1.34.0]) +]) +AM_CONDITIONAL(BUILDOPT_INTROSPECTION, test "x$found_introspection" = xyes) + +LIBGPGME_DEPENDENCY="1.1.8" +AC_ARG_WITH(gpgme, + AS_HELP_STRING([--with-gpgme], [Use gpgme @<:@default=yes@:>@]), + [], [with_gpgme=yes]) +AS_IF([test x$with_gpgme != xno], [ + PKG_CHECK_MODULES(OT_DEP_GPGME, gpgme-pthread >= $LIBGPGME_DEPENDENCY, have_gpgme=yes, [ + m4_ifdef([AM_PATH_GPGME_PTHREAD], [ + AM_PATH_GPGME_PTHREAD($LIBGPGME_DEPENDENCY, have_gpgme=yes, have_gpgme=no) + ],[ have_gpgme=no ]) + ]) + AS_IF([ test x$have_gpgme = xno ], [ + AC_MSG_ERROR([Need GPGME_PTHREAD version $LIBGPGME_DEPENDENCY or later]) + ]) + OSTREE_FEATURES="$OSTREE_FEATURES gpgme" + PKG_CHECK_MODULES(OT_DEP_GPG_ERROR, [gpg-error], [], [ +dnl This apparently doesn't ship a pkg-config file either, and we need +dnl to link to it directly. + AC_PATH_PROG(GPG_ERROR_CONFIG, [gpg-error-config], [AC_MSG_ERROR([Missing gpg-error-config])]) + OT_DEP_GPG_ERROR_CFLAGS="$( $GPG_ERROR_CONFIG --cflags )" + OT_DEP_GPG_ERROR_LIBS="$( $GPG_ERROR_CONFIG --libs )" + ]) + OT_DEP_GPGME_CFLAGS="${OT_DEP_GPGME_CFLAGS} ${OT_DEP_GPG_ERROR_CFLAGS}" + OT_DEP_GPGME_LIBS="${OT_DEP_GPGME_LIBS} ${OT_DEP_GPG_ERROR_LIBS}" + ], + [ + AC_DEFINE([OSTREE_DISABLE_GPGME], 1, [Define to disable internal GPGME support]) + with_gpgme=no + ] +) +AM_CONDITIONAL(USE_GPGME, test "x$have_gpgme" = xyes) + + +LIBSODIUM_DEPENDENCY="1.0.14" +AC_ARG_WITH(ed25519_libsodium, + AS_HELP_STRING([--with-ed25519-libsodium], [Use libsodium for ed25519 @<:@default=no@:>@]), + [], [with_ed25519_libsodium=no]) +AS_IF([test x$with_ed25519_libsodium != xno], [ + AC_DEFINE([HAVE_LIBSODIUM], 1, [Define if using libsodium]) + PKG_CHECK_MODULES(OT_DEP_LIBSODIUM, libsodium >= $LIBSODIUM_DEPENDENCY, have_libsodium=yes, have_libsodium=no) + AS_IF([ test x$have_libsodium = xno ], [ + AC_MSG_ERROR([Need LIBSODIUM version $LIBSODIUM_DEPENDENCY or later]) + ]) + OSTREE_FEATURES="$OSTREE_FEATURES sign-ed25519" +], with_ed25519_libsodium=no ) +AM_CONDITIONAL(USE_LIBSODIUM, test "x$have_libsodium" = xyes) + +LIBARCHIVE_DEPENDENCY="libarchive >= 2.8.0" +# What's in RHEL7.2. +FUSE_DEPENDENCY="fuse >= 2.9.2" + +AC_CHECK_HEADERS([linux/fsverity.h]) +AS_IF([test x$ac_cv_header_linux_fsverity_h = xyes ], + [OSTREE_FEATURES="$OSTREE_FEATURES ex-fsverity"]) + +# check for gtk-doc +m4_ifdef([GTK_DOC_CHECK], [ +GTK_DOC_CHECK([1.15], [--flavour no-tmpl]) +],[ +enable_gtk_doc=no +AM_CONDITIONAL([ENABLE_GTK_DOC], false) +]) + +AC_ARG_ENABLE(man, + [AS_HELP_STRING([--enable-man], + [generate man pages [default=auto]])],, + enable_man=maybe) + +AS_IF([test "$enable_man" != no], [ + AC_PATH_PROG([XSLTPROC], [xsltproc]) + AS_IF([test -z "$XSLTPROC"], [ + AS_IF([test "$enable_man" = yes], [ + AC_MSG_ERROR([xsltproc is required for --enable-man]) + ]) + enable_man=no + ],[ + enable_man=yes + ]) +]) +AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" != no) + +AC_ARG_ENABLE(rust, + [AS_HELP_STRING([--enable-rust], + [Compile Rust code instead of C [default=no]])],, + [enable_rust=no; rust_debug_release=no]) + +AS_IF([test "$enable_rust" = yes], [ + AC_PATH_PROG([cargo], [cargo]) + AS_IF([test -z "$cargo"], [AC_MSG_ERROR([cargo is required for --enable-rust])]) + AC_PATH_PROG([rustc], [rustc]) + AS_IF([test -z "$rustc"], [AC_MSG_ERROR([rustc is required for --enable-rust])]) + + dnl These bits based on gnome:librsvg/configure.ac + + dnl By default, we build in public release mode. + AC_ARG_ENABLE(rust-debug, + AC_HELP_STRING([--enable-rust-debug], + [Build Rust code with debugging information [default=no]]), + [rust_debug_release=$enableval], + [rust_debug_release=release]) + + AC_MSG_CHECKING(whether to build Rust code with debugging information) + if test "x$rust_debug_release" = "xyes" ; then + rust_debug_release=debug + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + RUST_TARGET_SUBDIR=${rust_debug_release} + AC_SUBST([RUST_TARGET_SUBDIR]) +]) +AM_CONDITIONAL(RUST_DEBUG, [test "x$rust_debug_release" = "xdebug"]) +AM_CONDITIONAL(ENABLE_RUST, [test "$enable_rust" != no]) + +AC_ARG_WITH(libarchive, + AS_HELP_STRING([--without-libarchive], [Do not use libarchive]), + :, with_libarchive=maybe) + +AS_IF([ test x$with_libarchive != xno ], [ + AC_MSG_CHECKING([for $LIBARCHIVE_DEPENDENCY]) + PKG_CHECK_EXISTS($LIBARCHIVE_DEPENDENCY, have_libarchive=yes, have_libarchive=no) + AC_MSG_RESULT([$have_libarchive]) + AS_IF([ test x$have_libarchive = xno && test x$with_libarchive != xmaybe ], [ + AC_MSG_ERROR([libarchive is enabled but could not be found]) + ]) + AS_IF([ test x$have_libarchive = xyes], [ + AC_DEFINE([HAVE_LIBARCHIVE], 1, [Define if we have libarchive.pc]) + PKG_CHECK_MODULES(OT_DEP_LIBARCHIVE, $LIBARCHIVE_DEPENDENCY) + save_LIBS=$LIBS + LIBS=$OT_DEP_LIBARCHIVE_LIBS + AC_CHECK_FUNCS(archive_read_support_filter_all) + LIBS=$save_LIBS + with_libarchive=yes + ], [ + with_libarchive=no + ]) +], [ with_libarchive=no ]) +if test x$with_libarchive != xno; then OSTREE_FEATURES="$OSTREE_FEATURES libarchive"; fi +AM_CONDITIONAL(USE_LIBARCHIVE, test $with_libarchive != no) + +dnl This is what is in RHEL7 anyways +SELINUX_DEPENDENCY="libselinux >= 2.1.13" + +AC_ARG_WITH(selinux, + AS_HELP_STRING([--without-selinux], [Do not use SELinux]), + :, with_selinux=maybe) + +AS_IF([ test x$with_selinux != xno ], [ + AC_MSG_CHECKING([for $SELINUX_DEPENDENCY]) + PKG_CHECK_EXISTS($SELINUX_DEPENDENCY, have_selinux=yes, have_selinux=no) + AC_MSG_RESULT([$have_selinux]) + AS_IF([ test x$have_selinux = xno && test x$with_selinux != xmaybe ], [ + AC_MSG_ERROR([SELinux is enabled but could not be found]) + ]) + AS_IF([ test x$have_selinux = xyes], [ + AC_DEFINE([HAVE_SELINUX], 1, [Define if we have libselinux.pc]) + PKG_CHECK_MODULES(OT_DEP_SELINUX, $SELINUX_DEPENDENCY) + with_selinux=yes + ], [ + with_selinux=no + ]) +], [ with_selinux=no ]) +if test x$with_selinux != xno; then OSTREE_FEATURES="$OSTREE_FEATURES selinux"; fi +AM_CONDITIONAL(USE_SELINUX, test $with_selinux != no) + +AC_ARG_WITH(smack, +AS_HELP_STRING([--with-smack], [Enable smack]), +:, with_smack=no) +AS_IF([ test x$with_smack = xyes], [ + AC_DEFINE([WITH_SMACK], 1, [Define if we have smack.pc]) +]) +AM_CONDITIONAL(USE_SMACK, test $with_smack != no) + +dnl crypto +AC_ARG_WITH(crypto, +AS_HELP_STRING([--with-crypto], [Choose library for checksums, one of glib, openssl, gnutls (default: glib)]), +:, with_crypto=glib) + +AS_IF([test $with_crypto = glib], + [], + [test $with_crypto = openssl], + [with_openssl=yes], + [test $with_crypto = gnutls], + [], + [AC_MSG_ERROR([Invalid --with-crypto $with_crypto])] + ) + +dnl begin openssl (really just libcrypto right now) +dnl Note this option is now deprecated in favor of --with-crypto=openssl +OPENSSL_DEPENDENCY="libcrypto >= 1.0.1" +AC_ARG_WITH(openssl, +AS_HELP_STRING([--with-openssl], [Enable use of OpenSSL libcrypto (checksums)]),with_openssl=$withval,with_openssl=no) +AS_IF([ test x$with_openssl != xno ], [ + PKG_CHECK_MODULES(OT_DEP_CRYPTO, $OPENSSL_DEPENDENCY) + AC_DEFINE([HAVE_OPENSSL], 1, [Define if we have openssl]) + with_crypto=openssl + with_openssl=yes +], [ + with_openssl=no +]) +if test x$with_openssl != xno; then OSTREE_FEATURES="$OSTREE_FEATURES openssl"; fi +AM_CONDITIONAL(USE_OPENSSL, test $with_openssl != no) +dnl end openssl + +dnl begin gnutls; in contrast to openssl this one only +dnl supports --with-crypto=gnutls +GNUTLS_DEPENDENCY="gnutls >= 3.5.0" +AS_IF([ test $with_crypto = gnutls ], [ + PKG_CHECK_MODULES(OT_DEP_CRYPTO, $GNUTLS_DEPENDENCY) + AC_DEFINE([HAVE_GNUTLS], 1, [Define if we have gnutls]) + OSTREE_FEATURES="$OSTREE_FEATURES gnutls" +]) +AM_CONDITIONAL(USE_GNUTLS, test $with_crypto = gnutls) +dnl end gnutls + +dnl Avahi dependency for finding repos +AVAHI_DEPENDENCY="avahi-client >= 0.6.31 avahi-glib >= 0.6.31" + +AC_ARG_WITH(avahi, + AS_HELP_STRING([--without-avahi], [Do not use Avahi]), + :, with_avahi=maybe) + +AS_IF([ test x$with_avahi != xno ], [ + AC_MSG_CHECKING([for $AVAHI_DEPENDENCY]) + PKG_CHECK_EXISTS($AVAHI_DEPENDENCY, have_avahi=yes, have_avahi=no) + AC_MSG_RESULT([$have_avahi]) + AS_IF([ test x$have_avahi = xno && test x$with_avahi != xmaybe ], [ + AC_MSG_ERROR([Avahi is enabled but could not be found]) + ]) + AS_IF([ test x$have_avahi = xyes], [ + AC_DEFINE([HAVE_AVAHI], 1, [Define if we have avahi-client.pc and avahi-glib.pc]) + PKG_CHECK_MODULES(OT_DEP_AVAHI, $AVAHI_DEPENDENCY) + with_avahi=yes + ], [ + with_avahi=no + ]) +], [ with_avahi=no ]) +if test x$with_avahi != xno; then OSTREE_FEATURES="$OSTREE_FEATURES avahi"; fi +AM_CONDITIONAL(USE_AVAHI, test $with_avahi != no) + +dnl This is what is in RHEL7.2 right now, picking it arbitrarily +LIBMOUNT_DEPENDENCY="mount >= 2.23.0" + +AC_ARG_WITH(libmount, + AS_HELP_STRING([--without-libmount], [Do not use libmount]), + :, with_libmount=maybe) + +AS_IF([ test x$with_libmount != xno ], [ + AC_MSG_CHECKING([for $LIBMOUNT_DEPENDENCY]) + PKG_CHECK_EXISTS($LIBMOUNT_DEPENDENCY, have_libmount=yes, have_libmount=no) + AC_MSG_RESULT([$have_libmount]) + AS_IF([ test x$have_libmount = xno && test x$with_libmount != xmaybe ], [ + AC_MSG_ERROR([libmount is enabled but could not be found]) + ]) + AS_IF([ test x$have_libmount = xyes], [ + AC_DEFINE([HAVE_LIBMOUNT], 1, [Define if we have libmount.pc]) + PKG_CHECK_MODULES(OT_DEP_LIBMOUNT, $LIBMOUNT_DEPENDENCY) + with_libmount=yes + save_LIBS=$LIBS + LIBS=$OT_DEP_LIBMOUNT_LIBS + AC_CHECK_FUNCS(mnt_unref_cache) + LIBS=$save_LIBS + ], [ + with_libmount=no + ]) +], [ with_libmount=no ]) +if test x$with_libmount != xno; then OSTREE_FEATURES="$OSTREE_FEATURES libmount"; fi +AM_CONDITIONAL(USE_LIBMOUNT, test $with_libmount != no) + +# Enabled by default because I think people should use it. +AC_ARG_ENABLE(rofiles-fuse, + [AS_HELP_STRING([--enable-rofiles-fuse], + [generate rofiles-fuse helper [default=yes]])],, + enable_rofiles_fuse=yes) +AS_IF([ test x$enable_rofiles_fuse != xno ], [ + PKG_CHECK_MODULES(BUILDOPT_FUSE, $FUSE_DEPENDENCY) +], [enable_rofiles_fuse=no]) +AM_CONDITIONAL(BUILDOPT_FUSE, test x$enable_rofiles_fuse = xyes) + +AC_ARG_WITH(dracut, + AS_HELP_STRING([--with-dracut], + [Install dracut module (default: no)]),, + [with_dracut=no]) +case x$with_dracut in + xno) ;; + xyes) ;; + xyesbutnoconf) ;; + *) AC_MSG_ERROR([Unknown --with-dracut value $with_dracut]) +esac +AM_CONDITIONAL(BUILDOPT_DRACUT, test x$with_dracut = xyes || test x$with_dracut = xyesbutnoconf) +AM_CONDITIONAL(BUILDOPT_DRACUT_CONF, test x$with_dracut = xyes) + +AC_ARG_WITH(mkinitcpio, + AS_HELP_STRING([--with-mkinitcpio], + [Install mkinitcpio module (default: no)]),, + [with_mkinitcpio=no]) +AM_CONDITIONAL(BUILDOPT_MKINITCPIO, test x$with_mkinitcpio = xyes) + +dnl We have separate checks for libsystemd and the unit dir for historical reasons +AC_ARG_WITH(libsystemd, + AS_HELP_STRING([--without-libsystemd], [Do not use libsystemd]), + :, with_libsystemd=maybe) + +AS_IF([ test x$with_libsystemd != xno ], [ + AC_MSG_CHECKING([for libsystemd]) + PKG_CHECK_EXISTS(libsystemd, have_libsystemd=yes, have_libsystemd=no) + AC_MSG_RESULT([$have_libsystemd]) + AS_IF([ test x$have_libsystemd = xno && test x$with_libsystemd != xmaybe ], [ + AC_MSG_ERROR([libsystemd is enabled but could not be found]) + ]) + AS_IF([ test x$have_libsystemd = xyes], [ + AC_DEFINE([HAVE_LIBSYSTEMD], 1, [Define if we have libsystemd.pc]) + PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd]) + with_libsystemd=yes + ], [ + with_libsystemd=no + ]) +], [ with_libsystemd=no ]) + +AS_IF([test "x$with_libsystemd" = "xyes"], [ + AC_ARG_WITH([systemdsystemunitdir], + AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), + [], + [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) + AS_IF([test "x$with_systemdsystemunitdir" != "xno"], [ + AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) + ]) + AC_ARG_WITH([systemdsystemgeneratordir], + AS_HELP_STRING([--with-systemdsystemgeneratordir=DIR], [Directory for systemd generators]), + [], + [with_systemdsystemgeneratordir=$($PKG_CONFIG --variable=systemdsystemgeneratordir systemd)]) + AS_IF([test "x$with_systemdsystemgeneratordir" != "xno"], [ + AC_SUBST([systemdsystemgeneratordir], [$with_systemdsystemgeneratordir]) + ]) +]) +AM_CONDITIONAL(BUILDOPT_SYSTEMD, test x$with_libsystemd = xyes) +dnl If we have both, we use the "new /var" model with ostree-system-generator +AM_CONDITIONAL(BUILDOPT_SYSTEMD_AND_LIBMOUNT,[test x$with_libsystemd = xyes && test x$with_libmount = xyes]) +AM_COND_IF(BUILDOPT_SYSTEMD_AND_LIBMOUNT, + AC_DEFINE([BUILDOPT_LIBSYSTEMD_AND_LIBMOUNT], 1, [Define if systemd and libmount])) +if test x$with_libsystemd = xyes; then OSTREE_FEATURES="$OSTREE_FEATURES systemd"; fi + +AC_ARG_WITH(builtin-grub2-mkconfig, + AS_HELP_STRING([--with-builtin-grub2-mkconfig], + [Use a builtin minimal grub2-mkconfig to generate a GRUB2 configuration file (default: no)]),, + [with_builtin_grub2_mkconfig=no]) +AM_CONDITIONAL(BUILDOPT_BUILTIN_GRUB2_MKCONFIG, test x$with_builtin_grub2_mkconfig = xyes) +AM_COND_IF(BUILDOPT_BUILTIN_GRUB2_MKCONFIG, + AC_DEFINE([USE_BUILTIN_GRUB2_MKCONFIG], 1, [Define if using internal ostree-grub-generator])) +AC_ARG_WITH(grub2-mkconfig-path, + AS_HELP_STRING([--with-grub2-mkconfig-path], + [Path to grub2-mkconfig])) +AS_IF([test x$with_grub2_mkconfig_path = x], [ + dnl Otherwise, look for the path to the system generator. On some + dnl distributions GRUB2 *-mkconfig executable has 'grub2' prefix and + dnl on some 'grub'. We default to grub2-mkconfig. + AC_CHECK_PROGS(GRUB2_MKCONFIG, [grub2-mkconfig grub-mkconfig], [grub2-mkconfig]) +],[GRUB2_MKCONFIG=$with_grub2_mkconfig_path]) +AC_DEFINE_UNQUOTED([GRUB2_MKCONFIG_PATH], ["$GRUB2_MKCONFIG"], [The system grub2-mkconfig executable name]) + +AC_ARG_WITH(static-compiler, + AS_HELP_STRING([--with-static-compiler], + [Use the given compiler to build ostree-prepare-root statically linked (default: no)]),, + [with_static_compiler=no]) +AM_CONDITIONAL(BUILDOPT_USE_STATIC_COMPILER, test "x$with_static_compiler" != xno) +AC_SUBST(STATIC_COMPILER, $with_static_compiler) + +dnl for tests (but we can't use asan with gjs or any introspection, +dnl see https://github.com/google/sanitizers/wiki/AddressSanitizerAsDso for more info) +AS_IF([test "x$found_introspection" = xyes && test x$using_asan != xyes], [ + AC_PATH_PROG(GJS, [gjs]) + if test -n "$GJS"; then + have_gjs=yes + else + have_gjs=no + fi +], [have_gjs=no]) +AM_CONDITIONAL(BUILDOPT_GJS, test x$have_gjs = xyes) + +# Do we enable building experimental (non-stable) API? +# The OSTREE_ENABLE_EXPERIMENTAL_API #define is used internally and in public +# headers, so any consumer of libostree who wants to use experimental API must +# #define OSTREE_ENABLE_EXPERIMENTAL_API 1 +# before including libostree headers. This means the name in the AC_DEFINE below +# is public API. +AC_ARG_ENABLE([experimental-api], + [AS_HELP_STRING([--enable-experimental-api], + [Enable unstable experimental API in libostree [default=no]])],, + [enable_experimental_api=no]) +AS_IF([test x$enable_experimental_api = xyes], + [AC_DEFINE([OSTREE_ENABLE_EXPERIMENTAL_API],[1],[Define if experimental API should be enabled]) + OSTREE_FEATURES="$OSTREE_FEATURES experimental"] +) +AM_CONDITIONAL([ENABLE_EXPERIMENTAL_API],[test x$enable_experimental_api = xyes]) +AM_CONDITIONAL([BUILDOPT_IS_DEVEL_BUILD],[test x$is_release_build != xyes]) +AM_COND_IF([BUILDOPT_IS_DEVEL_BUILD], + AC_DEFINE([BUILDOPT_IS_DEVEL_BUILD], [1], [Define if doing a development build]) + release_build_type=devel, + release_build_type=release) +OSTREE_FEATURES="$OSTREE_FEATURES $release_build_type" + +# P2P API is public in OSTree >= 2018.6 +OSTREE_FEATURES="$OSTREE_FEATURES p2p" + +# Strip leading whitespace +OSTREE_FEATURES=$(echo ${OSTREE_FEATURES}) + +AC_CONFIG_FILES([ +Makefile +apidoc/Makefile +src/libostree/ostree-1.pc +src/libostree/ostree-version.h +]) +AC_OUTPUT + +echo " + libostree $VERSION ($release_build_type) + features: $OSTREE_FEATURES + =============== + + + introspection: $found_introspection + Rust (internal oxidation): $rust_debug_release + rofiles-fuse: $enable_rofiles_fuse + HTTP backend: $fetcher_backend + \"ostree trivial-httpd\": $enable_trivial_httpd_cmdline + SELinux: $with_selinux + fs-verity: $ac_cv_header_linux_fsverity_h + cryptographic checksums: $with_crypto + systemd: $with_libsystemd + libmount: $with_libmount + libsodium (ed25519 signatures): $with_ed25519_libsodium + libarchive (parse tar files directly): $with_libarchive + static deltas: yes (always enabled now) + O_TMPFILE: $enable_otmpfile + wrpseudo-compat: $enable_wrpseudo_compat + man pages (xsltproc): $enable_man + api docs (gtk-doc): $enable_gtk_doc + installed tests: $enable_installed_tests + gjs-based tests: $have_gjs + dracut: $with_dracut + mkinitcpio: $with_mkinitcpio + Static compiler for ostree-prepare-root: $with_static_compiler + Experimental API $enable_experimental_api" +AS_IF([test x$with_builtin_grub2_mkconfig = xyes], [ + echo " builtin grub2-mkconfig (instead of system): $with_builtin_grub2_mkconfig" +], [ + echo " grub2-mkconfig path: $GRUB2_MKCONFIG" +]) +echo "" diff --git a/gtk-doc.make b/gtk-doc.make new file mode 100644 index 0000000..7d9a27f --- /dev/null +++ b/gtk-doc.make @@ -0,0 +1,321 @@ +# -*- mode: makefile -*- +# +# gtk-doc.make - make rules for gtk-doc +# Copyright (C) 2003 James Henstridge +# 2004-2007 Damon Chaplin +# 2007-2017 Stefan Sauer +# +# 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +#################################### +# Everything below here is generic # +#################################### + +if GTK_DOC_USE_LIBTOOL +GTKDOC_CC = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +GTKDOC_LD = $(LIBTOOL) --tag=CC --mode=link $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) +GTKDOC_RUN = $(LIBTOOL) --mode=execute +else +GTKDOC_CC = $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +GTKDOC_LD = $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) +GTKDOC_RUN = +endif + +# We set GPATH here; this gives us semantics for GNU make +# which are more like other make's VPATH, when it comes to +# whether a source that is a target of one rule is then +# searched for in VPATH/GPATH. +# +GPATH = $(srcdir) + +TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE) + +SETUP_FILES = \ + $(content_files) \ + $(expand_content_files) \ + $(DOC_MAIN_SGML_FILE) \ + $(DOC_MODULE)-sections.txt \ + $(DOC_MODULE)-overrides.txt + +EXTRA_DIST = \ + $(HTML_IMAGES) \ + $(SETUP_FILES) + +DOC_STAMPS=setup-build.stamp scan-build.stamp sgml-build.stamp \ + html-build.stamp pdf-build.stamp \ + sgml.stamp html.stamp pdf.stamp + +SCANOBJ_FILES = \ + $(DOC_MODULE).args \ + $(DOC_MODULE).hierarchy \ + $(DOC_MODULE).interfaces \ + $(DOC_MODULE).prerequisites \ + $(DOC_MODULE).signals + +REPORT_FILES = \ + $(DOC_MODULE)-undocumented.txt \ + $(DOC_MODULE)-undeclared.txt \ + $(DOC_MODULE)-unused.txt + +gtkdoc-check.test: Makefile + $(AM_V_GEN)echo "#!/bin/sh -e" > $@; \ + echo "$(GTKDOC_CHECK_PATH) || exit 1" >> $@; \ + chmod +x $@ + +CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS) gtkdoc-check.test + +if GTK_DOC_BUILD_HTML +HTML_BUILD_STAMP=html-build.stamp +else +HTML_BUILD_STAMP= +endif +if GTK_DOC_BUILD_PDF +PDF_BUILD_STAMP=pdf-build.stamp +else +PDF_BUILD_STAMP= +endif + +all-gtk-doc: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP) +.PHONY: all-gtk-doc + +if ENABLE_GTK_DOC +all-local: all-gtk-doc +endif + +docs: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP) + +$(REPORT_FILES): sgml-build.stamp + +#### setup #### + +GTK_DOC_V_SETUP=$(GTK_DOC_V_SETUP_@AM_V@) +GTK_DOC_V_SETUP_=$(GTK_DOC_V_SETUP_@AM_DEFAULT_V@) +GTK_DOC_V_SETUP_0=@echo " DOC Preparing build"; + +setup-build.stamp: + -$(GTK_DOC_V_SETUP)if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ + files=`echo $(SETUP_FILES) $(DOC_MODULE).types`; \ + if test "x$$files" != "x" ; then \ + for file in $$files ; do \ + destdir=`dirname $(abs_builddir)/$$file`; \ + test -d "$$destdir" || mkdir -p "$$destdir"; \ + test -f $(abs_srcdir)/$$file && \ + cp -pf $(abs_srcdir)/$$file $(abs_builddir)/$$file || true; \ + done; \ + fi; \ + fi + $(AM_V_at)touch setup-build.stamp + +#### scan #### + +GTK_DOC_V_SCAN=$(GTK_DOC_V_SCAN_@AM_V@) +GTK_DOC_V_SCAN_=$(GTK_DOC_V_SCAN_@AM_DEFAULT_V@) +GTK_DOC_V_SCAN_0=@echo " DOC Scanning header files"; + +GTK_DOC_V_INTROSPECT=$(GTK_DOC_V_INTROSPECT_@AM_V@) +GTK_DOC_V_INTROSPECT_=$(GTK_DOC_V_INTROSPECT_@AM_DEFAULT_V@) +GTK_DOC_V_INTROSPECT_0=@echo " DOC Introspecting gobjects"; + +scan-build.stamp: setup-build.stamp $(HFILE_GLOB) $(CFILE_GLOB) + $(GTK_DOC_V_SCAN)_source_dir='' ; \ + for i in $(DOC_SOURCE_DIR) ; do \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ + done ; \ + gtkdoc-scan --module=$(DOC_MODULE) --ignore-headers="$(IGNORE_HFILES)" $${_source_dir} $(SCAN_OPTIONS) $(EXTRA_HFILES) + $(GTK_DOC_V_INTROSPECT)if grep -l '^..*$$' $(DOC_MODULE).types > /dev/null 2>&1 ; then \ + scanobj_options=""; \ + gtkdoc-scangobj 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + scanobj_options="--verbose"; \ + fi; \ + fi; \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" \ + gtkdoc-scangobj $(SCANGOBJ_OPTIONS) $$scanobj_options --module=$(DOC_MODULE); \ + else \ + for i in $(SCANOBJ_FILES) ; do \ + test -f $$i || touch $$i ; \ + done \ + fi + $(AM_V_at)touch scan-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp + @true + +#### xml #### + +GTK_DOC_V_XML=$(GTK_DOC_V_XML_@AM_V@) +GTK_DOC_V_XML_=$(GTK_DOC_V_XML_@AM_DEFAULT_V@) +GTK_DOC_V_XML_0=@echo " DOC Building XML"; + +sgml-build.stamp: setup-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(HFILE_GLOB) $(CFILE_GLOB) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt $(expand_content_files) xml/gtkdocentities.ent + $(GTK_DOC_V_XML)_source_dir='' ; \ + for i in $(DOC_SOURCE_DIR) ; do \ + _source_dir="$${_source_dir} --source-dir=$$i" ; \ + done ; \ + gtkdoc-mkdb --module=$(DOC_MODULE) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $${_source_dir} $(MKDB_OPTIONS) + $(AM_V_at)touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +$(DOC_MAIN_SGML_FILE): sgml-build.stamp + @true + +xml/gtkdocentities.ent: Makefile + $(GTK_DOC_V_XML)$(MKDIR_P) $(@D) && ( \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + echo ""; \ + ) > $@ + +#### html #### + +GTK_DOC_V_HTML=$(GTK_DOC_V_HTML_@AM_V@) +GTK_DOC_V_HTML_=$(GTK_DOC_V_HTML_@AM_DEFAULT_V@) +GTK_DOC_V_HTML_0=@echo " DOC Building HTML"; + +GTK_DOC_V_XREF=$(GTK_DOC_V_XREF_@AM_V@) +GTK_DOC_V_XREF_=$(GTK_DOC_V_XREF_@AM_DEFAULT_V@) +GTK_DOC_V_XREF_0=@echo " DOC Fixing cross-references"; + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files) + $(GTK_DOC_V_HTML)rm -rf html && mkdir html && \ + mkhtml_options=""; \ + gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + mkhtml_options="$$mkhtml_options --verbose"; \ + fi; \ + fi; \ + gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \ + if test "$$?" = "0"; then \ + mkhtml_options="$$mkhtml_options --path=\"$(abs_srcdir)\""; \ + fi; \ + cd html && gtkdoc-mkhtml $$mkhtml_options $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) + -@test "x$(HTML_IMAGES)" = "x" || \ + for file in $(HTML_IMAGES) ; do \ + test -f $(abs_srcdir)/$$file && cp $(abs_srcdir)/$$file $(abs_builddir)/html; \ + test -f $(abs_builddir)/$$file && cp $(abs_builddir)/$$file $(abs_builddir)/html; \ + test -f $$file && cp $$file $(abs_builddir)/html; \ + done; + $(GTK_DOC_V_XREF)gtkdoc-fixxref --module=$(DOC_MODULE) --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + $(AM_V_at)touch html-build.stamp + +#### pdf #### + +GTK_DOC_V_PDF=$(GTK_DOC_V_PDF_@AM_V@) +GTK_DOC_V_PDF_=$(GTK_DOC_V_PDF_@AM_DEFAULT_V@) +GTK_DOC_V_PDF_0=@echo " DOC Building PDF"; + +pdf-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) $(expand_content_files) + $(GTK_DOC_V_PDF)rm -f $(DOC_MODULE).pdf && \ + mkpdf_options=""; \ + gtkdoc-mkpdf 2>&1 --help | grep >/dev/null "\-\-verbose"; \ + if test "$$?" = "0"; then \ + if test "x$(V)" = "x1"; then \ + mkpdf_options="$$mkpdf_options --verbose"; \ + fi; \ + fi; \ + if test "x$(HTML_IMAGES)" != "x"; then \ + for img in $(HTML_IMAGES); do \ + part=`dirname $$img`; \ + echo $$mkpdf_options | grep >/dev/null "\-\-imgdir=$$part "; \ + if test $$? != 0; then \ + mkpdf_options="$$mkpdf_options --imgdir=$$part"; \ + fi; \ + done; \ + fi; \ + gtkdoc-mkpdf --path="$(abs_srcdir)" $$mkpdf_options $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) $(MKPDF_OPTIONS) + $(AM_V_at)touch pdf-build.stamp + +############## + +clean-local: + @rm -f *~ *.bak + @rm -rf .libs + @if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-types" ; then \ + rm -f $(DOC_MODULE).types; \ + fi + @if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-sections" ; then \ + rm -f $(DOC_MODULE)-sections.txt; \ + fi + +distclean-local: + @rm -rf xml html $(REPORT_FILES) $(DOC_MODULE).pdf \ + $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt + @if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \ + rm -f $(SETUP_FILES) $(DOC_MODULE).types; \ + fi + +maintainer-clean-local: + @rm -rf xml html + +install-data-local: + @installfiles=`echo $(builddir)/html/*`; \ + if test "$$installfiles" = '$(builddir)/html/*'; \ + then echo 1>&2 'Nothing to install' ; \ + else \ + if test -n "$(DOC_MODULE_VERSION)"; then \ + installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ + else \ + installdir="$(DESTDIR)$(TARGET_DIR)"; \ + fi; \ + $(mkinstalldirs) $${installdir} ; \ + for i in $$installfiles; do \ + echo ' $(INSTALL_DATA) '$$i ; \ + $(INSTALL_DATA) $$i $${installdir}; \ + done; \ + if test -n "$(DOC_MODULE_VERSION)"; then \ + mv -f $${installdir}/$(DOC_MODULE).devhelp2 \ + $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp2; \ + fi; \ + $(GTKDOC_REBASE) --relative --dest-dir=$(DESTDIR) --html-dir=$${installdir}; \ + fi + +uninstall-local: + @if test -n "$(DOC_MODULE_VERSION)"; then \ + installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ + else \ + installdir="$(DESTDIR)$(TARGET_DIR)"; \ + fi; \ + rm -rf $${installdir} + +# +# Require gtk-doc when making dist +# +if HAVE_GTK_DOC +dist-check-gtkdoc: docs +else +dist-check-gtkdoc: + @echo "*** gtk-doc is needed to run 'make dist'. ***" + @echo "*** gtk-doc was not found when 'configure' ran. ***" + @echo "*** please install gtk-doc and rerun 'configure'. ***" + @false +endif + +dist-hook: dist-check-gtkdoc all-gtk-doc dist-hook-local + @mkdir $(distdir)/html + @cp ./html/* $(distdir)/html + @-cp ./$(DOC_MODULE).pdf $(distdir)/ + @-cp ./$(DOC_MODULE).types $(distdir)/ + @-cp ./$(DOC_MODULE)-sections.txt $(distdir)/ + @cd $(distdir) && rm -f $(DISTCLEANFILES) + @$(GTKDOC_REBASE) --online --relative --html-dir=$(distdir)/html + +.PHONY : dist-hook-local docs diff --git a/libglnx/COPYING b/libglnx/COPYING new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/libglnx/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 General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/libglnx/Makefile-libglnx.am b/libglnx/Makefile-libglnx.am new file mode 100644 index 0000000..957eae9 --- /dev/null +++ b/libglnx/Makefile-libglnx.am @@ -0,0 +1,80 @@ +# Copyright (C) 2015 Colin Walters +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +EXTRA_DIST += \ + $(libglnx_srcpath)/README.md \ + $(libglnx_srcpath)/COPYING \ + $(libglnx_srcpath)/libglnx.m4 \ + $(NULL) + +libglnx_la_SOURCES = \ + $(libglnx_srcpath)/glnx-macros.h \ + $(libglnx_srcpath)/glnx-backport-autocleanups.h \ + $(libglnx_srcpath)/glnx-backport-autoptr.h \ + $(libglnx_srcpath)/glnx-backports.h \ + $(libglnx_srcpath)/glnx-backports.c \ + $(libglnx_srcpath)/glnx-local-alloc.h \ + $(libglnx_srcpath)/glnx-local-alloc.c \ + $(libglnx_srcpath)/glnx-errors.h \ + $(libglnx_srcpath)/glnx-errors.c \ + $(libglnx_srcpath)/glnx-console.h \ + $(libglnx_srcpath)/glnx-console.c \ + $(libglnx_srcpath)/glnx-dirfd.h \ + $(libglnx_srcpath)/glnx-dirfd.c \ + $(libglnx_srcpath)/glnx-fdio.h \ + $(libglnx_srcpath)/glnx-fdio.c \ + $(libglnx_srcpath)/glnx-lockfile.h \ + $(libglnx_srcpath)/glnx-lockfile.c \ + $(libglnx_srcpath)/glnx-missing-syscall.h \ + $(libglnx_srcpath)/glnx-missing.h \ + $(libglnx_srcpath)/glnx-xattrs.h \ + $(libglnx_srcpath)/glnx-xattrs.c \ + $(libglnx_srcpath)/glnx-shutil.h \ + $(libglnx_srcpath)/glnx-shutil.c \ + $(libglnx_srcpath)/libglnx.h \ + $(libglnx_srcpath)/tests/libglnx-testlib.h \ + $(NULL) + +libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic +libglnx_la_LIBADD = $(libglnx_libs) + +libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros test-libglnx-shutil +TESTS += $(libglnx_tests) + +libglnx_testlib_sources = $(libglnx_srcpath)/tests/libglnx-testlib.c + +check_PROGRAMS += $(libglnx_tests) +test_libglnx_xattrs_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-xattrs.c +test_libglnx_xattrs_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_xattrs_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_fdio_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-fdio.c +test_libglnx_fdio_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_fdio_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_errors_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-errors.c +test_libglnx_errors_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_errors_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_macros_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-macros.c +test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_shutil_SOURCES = $(libglnx_testlib_sources) $(libglnx_srcpath)/tests/test-libglnx-shutil.c +test_libglnx_shutil_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_shutil_LDADD = $(libglnx_libs) libglnx.la diff --git a/libglnx/Makefile-libglnx.am.inc b/libglnx/Makefile-libglnx.am.inc new file mode 100644 index 0000000..4465f46 --- /dev/null +++ b/libglnx/Makefile-libglnx.am.inc @@ -0,0 +1,80 @@ +# Copyright (C) 2015 Colin Walters +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +EXTRA_DIST += \ + libglnx/README.md \ + libglnx/COPYING \ + libglnx/libglnx.m4 \ + $(NULL) + +libglnx_la_SOURCES = \ + libglnx/glnx-macros.h \ + libglnx/glnx-backport-autocleanups.h \ + libglnx/glnx-backport-autoptr.h \ + libglnx/glnx-backports.h \ + libglnx/glnx-backports.c \ + libglnx/glnx-local-alloc.h \ + libglnx/glnx-local-alloc.c \ + libglnx/glnx-errors.h \ + libglnx/glnx-errors.c \ + libglnx/glnx-console.h \ + libglnx/glnx-console.c \ + libglnx/glnx-dirfd.h \ + libglnx/glnx-dirfd.c \ + libglnx/glnx-fdio.h \ + libglnx/glnx-fdio.c \ + libglnx/glnx-lockfile.h \ + libglnx/glnx-lockfile.c \ + libglnx/glnx-missing-syscall.h \ + libglnx/glnx-missing.h \ + libglnx/glnx-xattrs.h \ + libglnx/glnx-xattrs.c \ + libglnx/glnx-shutil.h \ + libglnx/glnx-shutil.c \ + libglnx/libglnx.h \ + libglnx/tests/libglnx-testlib.h \ + $(NULL) + +libglnx_la_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +libglnx_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^glnx_" -no-undefined -export-dynamic +libglnx_la_LIBADD = $(libglnx_libs) + +libglnx_tests = test-libglnx-xattrs test-libglnx-fdio test-libglnx-errors test-libglnx-macros test-libglnx-shutil +TESTS += $(libglnx_tests) + +libglnx_testlib_sources = libglnx/tests/libglnx-testlib.c + +check_PROGRAMS += $(libglnx_tests) +test_libglnx_xattrs_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-xattrs.c +test_libglnx_xattrs_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_xattrs_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_fdio_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-fdio.c +test_libglnx_fdio_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_fdio_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_errors_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-errors.c +test_libglnx_errors_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_errors_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_macros_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-macros.c +test_libglnx_macros_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_macros_LDADD = $(libglnx_libs) libglnx.la + +test_libglnx_shutil_SOURCES = $(libglnx_testlib_sources) libglnx/tests/test-libglnx-shutil.c +test_libglnx_shutil_CFLAGS = $(AM_CFLAGS) $(libglnx_cflags) +test_libglnx_shutil_LDADD = $(libglnx_libs) libglnx.la diff --git a/libglnx/README.md b/libglnx/README.md new file mode 100644 index 0000000..587e5d4 --- /dev/null +++ b/libglnx/README.md @@ -0,0 +1,76 @@ +libglnx is the successor to [libgsystem](https://gitlab.gnome.org/Archive/libgsystem). + +It is for modules which depend on both GLib and Linux, intended to be +used as a git submodule. + +Features: + + - File APIs which use `openat()` like APIs, but also take a `GCancellable` + to support dynamic cancellation + - APIs also have a `GError` parameter + - High level "shutil", somewhat inspired by Python's + - A "console" API for tty output + - A backport of the GLib cleanup macros for projects which can't yet take + a dependency on 2.40. + +Why? +---- + +There are multiple projects which have a hard dependency on Linux and +GLib, such as NetworkManager, ostree, flatpak, etc. It makes sense +for them to be able to share Linux-specific APIs. + +This module also contains some code taken from systemd, which has very +high quality LGPLv2+ shared library code, but most of the internal +shared library is private, and not namespaced. + +One could also compare this project to gnulib; the salient differences +there are that at least some of this module is eventually destined for +inclusion in GLib. + +Adding this to your project +--------------------------- + +## Meson + +First, set up a Git submodule: + +``` +git submodule add https://gitlab.gnome.org/GNOME/libglnx subprojects/libglnx +``` + +Or a Git [subtree](https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt): + +``` +git remote add libglnx https://gitlab.gnome.org/GNOME/libglnx.git +git fetch libglnx +git subtree add -P subprojects/libglnx libglnx/master +``` + +Then, in your top-level `meson.build`: + +``` +libglnx_dep = subproject('libglnx').get_variable('libglnx_dep') +# now use libglnx_dep in your dependencies +``` + +Porting from libgsystem +----------------------- + +For all of the filesystem access code, libglnx exposes only +fd-relative API, not `GFile*`. It does use `GCancellable` where +applicable. + +For local allocation macros, you should start using the `g_auto` +macros from GLib. A backport is included in libglnx. There are a few +APIs not defined in GLib yet, such as `glnx_autofd`. + +`gs_transfer_out_value` is replaced by `g_steal_pointer`. + +Contributing +------------ + +Development happens in GNOME Gitlab: https://gitlab.gnome.org/GNOME/libglnx + +(If you're seeing this on the Github mirror, we used to do development + on Github but that was before GNOME deployed Gitlab.) diff --git a/libglnx/glnx-backport-autocleanups.h b/libglnx/glnx-backport-autocleanups.h new file mode 100644 index 0000000..50f469f --- /dev/null +++ b/libglnx/glnx-backport-autocleanups.h @@ -0,0 +1,135 @@ +/* + * Copyright © 2015 Canonical Limited + * + * 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 of the licence, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Author: Ryan Lortie + */ + +#pragma once + +#include + +#if !GLIB_CHECK_VERSION(2, 43, 4) + +static inline void +g_autoptr_cleanup_generic_gfree (void *p) +{ + void **pp = (void**)p; + if (*pp) + g_free (*pp); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GAsyncQueue, g_async_queue_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GBookmarkFile, g_bookmark_file_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GBytes, g_bytes_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GChecksum, g_checksum_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDateTime, g_date_time_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDir, g_dir_close) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GError, g_error_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GHashTable, g_hash_table_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GHmac, g_hmac_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GIOChannel, g_io_channel_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GKeyFile, g_key_file_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GList, g_list_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GArray, g_array_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GPtrArray, g_ptr_array_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainContext, g_main_context_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMainLoop, g_main_loop_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSource, g_source_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMappedFile, g_mapped_file_unref) +#if GLIB_CHECK_VERSION(2, 36, 0) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMarkupParseContext, g_markup_parse_context_unref) +#endif +G_DEFINE_AUTOPTR_CLEANUP_FUNC(gchar, g_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GNode, g_node_destroy) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOptionContext, g_option_context_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOptionGroup, g_option_group_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GPatternSpec, g_pattern_spec_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GQueue, g_queue_free) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GQueue, g_queue_clear) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRand, g_rand_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GRegex, g_regex_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMatchInfo, g_match_info_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GScanner, g_scanner_destroy) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSequence, g_sequence_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSList, g_slist_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GStringChunk, g_string_chunk_free) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(GStrv, g_strfreev, NULL) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GThread, g_thread_unref) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GMutex, g_mutex_clear) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GCond, g_cond_clear) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTimer, g_timer_destroy) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTimeZone, g_time_zone_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTree, g_tree_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariant, g_variant_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantBuilder, g_variant_builder_unref) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantBuilder, g_variant_builder_clear) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantIter, g_variant_iter_free) +#if GLIB_CHECK_VERSION(2, 40, 0) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantDict, g_variant_dict_unref) +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GVariantDict, g_variant_dict_clear) +#endif +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVariantType, g_variant_type_free) +#if GLIB_CHECK_VERSION(2, 40, 0) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSubprocess, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSubprocessLauncher, g_object_unref) +#endif + +/* Add GObject-based types as needed. */ +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GAsyncResult, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GCancellable, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GConverter, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GConverterOutputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDataInputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFile, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileEnumerator, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileIOStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileInfo, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileInputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileMonitor, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileOutputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GInputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMemoryInputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMemoryOutputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GMount, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GOutputStream, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSocket, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GSocketAddress, g_object_unref) +#if GLIB_CHECK_VERSION(2, 36, 0) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTask, g_object_unref) +#endif +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTlsCertificate, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTlsDatabase, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTlsInteraction, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDBusConnection, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GDBusMessage, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVolumeMonitor, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GZlibCompressor, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GZlibDecompressor, g_object_unref) + +#endif + +#if !GLIB_CHECK_VERSION(2, 45, 8) + +static inline void +g_autoptr_cleanup_gstring_free (GString *string) +{ + if (string) + g_string_free (string, TRUE); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GString, g_autoptr_cleanup_gstring_free) + +#endif diff --git a/libglnx/glnx-backport-autoptr.h b/libglnx/glnx-backport-autoptr.h new file mode 100644 index 0000000..b36919d --- /dev/null +++ b/libglnx/glnx-backport-autoptr.h @@ -0,0 +1,133 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Colin Walters + * + * GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#if !GLIB_CHECK_VERSION(2, 43, 4) + +#define _GLIB_AUTOPTR_FUNC_NAME(TypeName) glib_autoptr_cleanup_##TypeName +#define _GLIB_AUTOPTR_TYPENAME(TypeName) TypeName##_autoptr +#define _GLIB_AUTO_FUNC_NAME(TypeName) glib_auto_cleanup_##TypeName +#define _GLIB_CLEANUP(func) __attribute__((cleanup(func))) +#define _GLIB_DEFINE_AUTOPTR_CHAINUP(ModuleObjName, ParentName) \ + typedef ModuleObjName *_GLIB_AUTOPTR_TYPENAME(ModuleObjName); \ + static inline void _GLIB_AUTOPTR_FUNC_NAME(ModuleObjName) (ModuleObjName **_ptr) { \ + _GLIB_AUTOPTR_FUNC_NAME(ParentName) ((ParentName **) _ptr); } \ + + +/* these macros are API */ +#define G_DEFINE_AUTOPTR_CLEANUP_FUNC(TypeName, func) \ + typedef TypeName *_GLIB_AUTOPTR_TYPENAME(TypeName); \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + static inline void _GLIB_AUTOPTR_FUNC_NAME(TypeName) (TypeName **_ptr) { if (*_ptr) (func) (*_ptr); } \ + G_GNUC_END_IGNORE_DEPRECATIONS +#define G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TypeName, func) \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + static inline void _GLIB_AUTO_FUNC_NAME(TypeName) (TypeName *_ptr) { (func) (_ptr); } \ + G_GNUC_END_IGNORE_DEPRECATIONS +#define G_DEFINE_AUTO_CLEANUP_FREE_FUNC(TypeName, func, none) \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + static inline void _GLIB_AUTO_FUNC_NAME(TypeName) (TypeName *_ptr) { if (*_ptr != none) (func) (*_ptr); } \ + G_GNUC_END_IGNORE_DEPRECATIONS +#define g_autoptr(TypeName) _GLIB_CLEANUP(_GLIB_AUTOPTR_FUNC_NAME(TypeName)) _GLIB_AUTOPTR_TYPENAME(TypeName) +#define g_auto(TypeName) _GLIB_CLEANUP(_GLIB_AUTO_FUNC_NAME(TypeName)) TypeName +#define g_autofree _GLIB_CLEANUP(g_autoptr_cleanup_generic_gfree) + +/** + * g_steal_pointer: + * @pp: a pointer to a pointer + * + * Sets @pp to %NULL, returning the value that was there before. + * + * Conceptually, this transfers the ownership of the pointer from the + * referenced variable to the "caller" of the macro (ie: "steals" the + * reference). + * + * The return value will be properly typed, according to the type of + * @pp. + * + * This can be very useful when combined with g_autoptr() to prevent the + * return value of a function from being automatically freed. Consider + * the following example (which only works on GCC and clang): + * + * |[ + * GObject * + * create_object (void) + * { + * g_autoptr(GObject) obj = g_object_new (G_TYPE_OBJECT, NULL); + * + * if (early_error_case) + * return NULL; + * + * return g_steal_pointer (&obj); + * } + * ]| + * + * It can also be used in similar ways for 'out' parameters and is + * particularly useful for dealing with optional out parameters: + * + * |[ + * gboolean + * get_object (GObject **obj_out) + * { + * g_autoptr(GObject) obj = g_object_new (G_TYPE_OBJECT, NULL); + * + * if (early_error_case) + * return FALSE; + * + * if (obj_out) + * *obj_out = g_steal_pointer (&obj); + * + * return TRUE; + * } + * ]| + * + * In the above example, the object will be automatically freed in the + * early error case and also in the case that %NULL was given for + * @obj_out. + * + * Since: 2.44 + */ +static inline gpointer +(g_steal_pointer) (gpointer pp) +{ + gpointer *ptr = (gpointer *) pp; + gpointer ref; + + ref = *ptr; + *ptr = NULL; + + return ref; +} + +/* type safety */ +#define g_steal_pointer(pp) \ + (0 ? (*(pp)) : (g_steal_pointer) (pp)) + +#endif /* !GLIB_CHECK_VERSION(2, 43, 3) */ + +G_END_DECLS diff --git a/libglnx/glnx-backports.c b/libglnx/glnx-backports.c new file mode 100644 index 0000000..c7bb600 --- /dev/null +++ b/libglnx/glnx-backports.c @@ -0,0 +1,61 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "glnx-backports.h" + +#if !GLIB_CHECK_VERSION(2, 44, 0) +gboolean +glnx_strv_contains (const gchar * const *strv, + const gchar *str) +{ + g_return_val_if_fail (strv != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + for (; *strv != NULL; strv++) + { + if (g_str_equal (str, *strv)) + return TRUE; + } + + return FALSE; +} + +gboolean +glnx_set_object (GObject **object_ptr, + GObject *new_object) +{ + GObject *old_object = *object_ptr; + + if (old_object == new_object) + return FALSE; + + if (new_object != NULL) + g_object_ref (new_object); + + *object_ptr = new_object; + + if (old_object != NULL) + g_object_unref (old_object); + + return TRUE; +} +#endif diff --git a/libglnx/glnx-backports.h b/libglnx/glnx-backports.h new file mode 100644 index 0000000..6c39cf2 --- /dev/null +++ b/libglnx/glnx-backports.h @@ -0,0 +1,78 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Colin Walters + * + * GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#if !GLIB_CHECK_VERSION(2, 34, 0) +#define g_clear_pointer(pp, destroy) \ + G_STMT_START { \ + G_STATIC_ASSERT (sizeof *(pp) == sizeof (gpointer)); \ + /* Only one access, please; work around type aliasing */ \ + union { char *in; gpointer *out; } _pp; \ + gpointer _p; \ + /* This assignment is needed to avoid a gcc warning */ \ + GDestroyNotify _destroy = (GDestroyNotify) (destroy); \ + \ + _pp.in = (char *) (pp); \ + _p = *_pp.out; \ + if (_p) \ + { \ + *_pp.out = NULL; \ + _destroy (_p); \ + } \ + } G_STMT_END +#endif + +#if !GLIB_CHECK_VERSION(2, 44, 0) + +#define g_strv_contains glnx_strv_contains +gboolean glnx_strv_contains (const gchar * const *strv, + const gchar *str); + +#define g_set_object(object_ptr, new_object) \ + (/* Check types match. */ \ + 0 ? *(object_ptr) = (new_object), FALSE : \ + glnx_set_object ((GObject **) (object_ptr), (GObject *) (new_object)) \ + ) +gboolean glnx_set_object (GObject **object_ptr, + GObject *new_object); + +#endif /* !GLIB_CHECK_VERSION(2, 44, 0) */ + +#ifndef g_assert_nonnull +#define g_assert_nonnull(x) g_assert (x != NULL) +#endif + +#ifndef g_assert_null +#define g_assert_null(x) g_assert (x == NULL) +#endif + +#if !GLIB_CHECK_VERSION (2, 38, 0) +#define g_test_skip(s) g_test_message ("SKIP: %s", s) +#endif + +G_END_DECLS diff --git a/libglnx/glnx-console.c b/libglnx/glnx-console.c new file mode 100644 index 0000000..c2fe29d --- /dev/null +++ b/libglnx/glnx-console.c @@ -0,0 +1,359 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013,2014,2015 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "glnx-console.h" + +#include +#include +#include +#include +#include +#include + +/* For people with widescreen monitors and maximized terminals, it looks pretty + * bad to have an enormous progress bar. For much the same reason as web pages + * tend to have a maximum width; + * https://ux.stackexchange.com/questions/48982/suggest-good-max-width-for-fluid-width-design + */ +#define MAX_PROGRESSBAR_COLUMNS 20 + +/* Max updates output per second. On a tty there's no point to rendering + * extremely fast; and for a non-tty we're probably in a Jenkins job + * or whatever and having percentages spam multiple lines there is annoying. + */ +#define MAX_TTY_UPDATE_HZ (5) +#define MAX_NONTTY_UPDATE_HZ (1) + +static gboolean locked; +static guint64 last_update_ms; /* monotonic time in millis we last updated */ + +gboolean +glnx_stdout_is_tty (void) +{ + static gsize initialized = 0; + static gboolean stdout_is_tty_v; + + if (g_once_init_enter (&initialized)) + { + stdout_is_tty_v = isatty (1); + g_once_init_leave (&initialized, 1); + } + + return stdout_is_tty_v; +} + +static volatile guint cached_columns = 0; +static volatile guint cached_lines = 0; + +static int +fd_columns (int fd) +{ + struct winsize ws = {}; + + if (ioctl (fd, TIOCGWINSZ, &ws) < 0) + return -errno; + + if (ws.ws_col <= 0) + return -EIO; + + return ws.ws_col; +} + +/** + * glnx_console_columns: + * + * Returns: The number of columns for terminal output + */ +guint +glnx_console_columns (void) +{ + if (G_UNLIKELY (cached_columns == 0)) + { + int c; + + c = fd_columns (STDOUT_FILENO); + + if (c <= 0) + c = 80; + + if (c > 256) + c = 256; + + cached_columns = c; + } + + return cached_columns; +} + +static int +fd_lines (int fd) +{ + struct winsize ws = {}; + + if (ioctl (fd, TIOCGWINSZ, &ws) < 0) + return -errno; + + if (ws.ws_row <= 0) + return -EIO; + + return ws.ws_row; +} + +/** + * glnx_console_lines: + * + * Returns: The number of lines for terminal output + */ +guint +glnx_console_lines (void) +{ + if (G_UNLIKELY (cached_lines == 0)) + { + int l; + + l = fd_lines (STDOUT_FILENO); + + if (l <= 0) + l = 24; + + cached_lines = l; + } + + return cached_lines; +} + +static void +on_sigwinch (int signum) +{ + cached_columns = 0; + cached_lines = 0; +} + +void +glnx_console_lock (GLnxConsoleRef *console) +{ + static gsize sigwinch_initialized = 0; + + g_return_if_fail (!locked); + g_return_if_fail (!console->locked); + + console->is_tty = glnx_stdout_is_tty (); + + locked = console->locked = TRUE; + + if (console->is_tty) + { + if (g_once_init_enter (&sigwinch_initialized)) + { + signal (SIGWINCH, on_sigwinch); + g_once_init_leave (&sigwinch_initialized, 1); + } + + { static const char initbuf[] = { 0x1B, 0x37 }; + (void) fwrite (initbuf, 1, sizeof (initbuf), stdout); + } + } +} + +static void +printpad (const char *padbuf, + guint padbuf_len, + guint n) +{ + const guint d = n / padbuf_len; + const guint r = n % padbuf_len; + guint i; + + for (i = 0; i < d; i++) + fwrite (padbuf, 1, padbuf_len, stdout); + fwrite (padbuf, 1, r, stdout); +} + +static void +text_percent_internal (const char *text, + int percentage) +{ + /* Check whether we're trying to render too fast; unless percentage is 100, in + * which case we assume this is the last call, so we always render it. + */ + const guint64 current_ms = g_get_monotonic_time () / 1000; + if (percentage != 100) + { + const guint64 diff_ms = current_ms - last_update_ms; + if (glnx_stdout_is_tty ()) + { + if (diff_ms < (1000/MAX_TTY_UPDATE_HZ)) + return; + } + else + { + if (diff_ms < (1000/MAX_NONTTY_UPDATE_HZ)) + return; + } + } + last_update_ms = current_ms; + + static const char equals[] = "===================="; + const guint n_equals = sizeof (equals) - 1; + static const char spaces[] = " "; + const guint n_spaces = sizeof (spaces) - 1; + const guint ncolumns = glnx_console_columns (); + const guint bar_min = 10; + + if (text && !*text) + text = NULL; + + const guint input_textlen = text ? strlen (text) : 0; + + if (!glnx_stdout_is_tty ()) + { + if (text) + fprintf (stdout, "%s", text); + if (percentage != -1) + { + if (text) + fputc (' ', stdout); + fprintf (stdout, "%u%%", percentage); + } + fputc ('\n', stdout); + fflush (stdout); + return; + } + + if (ncolumns < bar_min) + return; /* TODO: spinner */ + + /* Restore cursor */ + { const char beginbuf[2] = { 0x1B, 0x38 }; + (void) fwrite (beginbuf, 1, sizeof (beginbuf), stdout); + } + + if (percentage == -1) + { + if (text != NULL) + fwrite (text, 1, input_textlen, stdout); + + /* Overwrite remaining space, if any */ + if (ncolumns > input_textlen) + printpad (spaces, n_spaces, ncolumns - input_textlen); + } + else + { + const guint textlen = MIN (input_textlen, ncolumns - bar_min); + const guint barlen = MIN (MAX_PROGRESSBAR_COLUMNS, ncolumns - (textlen + 1)); + + if (textlen > 0) + { + fwrite (text, 1, textlen, stdout); + fputc (' ', stdout); + } + + { + const guint nbraces = 2; + const guint textpercent_len = 5; + const guint bar_internal_len = barlen - nbraces - textpercent_len; + const guint eqlen = bar_internal_len * (percentage / 100.0); + const guint spacelen = bar_internal_len - eqlen; + + fputc ('[', stdout); + printpad (equals, n_equals, eqlen); + printpad (spaces, n_spaces, spacelen); + fputc (']', stdout); + fprintf (stdout, " %3d%%", percentage); + } + } + + fflush (stdout); +} + +/** + * glnx_console_progress_text_percent: + * @text: Show this text before the progress bar + * @percentage: An integer in the range of 0 to 100 + * + * On a tty, print to the console @text followed by an ASCII art + * progress bar whose percentage is @percentage. If stdout is not a + * tty, a more basic line by line change will be printed. + * + * You must have called glnx_console_lock() before invoking this + * function. + * + */ +void +glnx_console_progress_text_percent (const char *text, + guint percentage) +{ + g_return_if_fail (percentage <= 100); + + text_percent_internal (text, percentage); +} + +/** + * glnx_console_progress_n_items: + * @text: Show this text before the progress bar + * @current: An integer for how many items have been processed + * @total: An integer for how many items there are total + * + * On a tty, print to the console @text followed by [@current/@total], + * then an ASCII art progress bar, like glnx_console_progress_text_percent(). + * + * You must have called glnx_console_lock() before invoking this + * function. + */ +void +glnx_console_progress_n_items (const char *text, + guint current, + guint total) +{ + g_return_if_fail (current <= total); + g_return_if_fail (total > 0); + + g_autofree char *newtext = g_strdup_printf ("%s (%u/%u)", text, current, total); + /* Special case current == total to ensure we end at 100% */ + int percentage = (current == total) ? 100 : (((double)current) / total * 100); + glnx_console_progress_text_percent (newtext, percentage); +} + +void +glnx_console_text (const char *text) +{ + text_percent_internal (text, -1); +} + +/** + * glnx_console_unlock: + * + * Print a newline, and reset all cached console progress state. + * + * This function does nothing if stdout is not a tty. + */ +void +glnx_console_unlock (GLnxConsoleRef *console) +{ + g_return_if_fail (locked); + g_return_if_fail (console->locked); + + if (console->is_tty) + fputc ('\n', stdout); + + locked = console->locked = FALSE; +} diff --git a/libglnx/glnx-console.h b/libglnx/glnx-console.h new file mode 100644 index 0000000..d853a80 --- /dev/null +++ b/libglnx/glnx-console.h @@ -0,0 +1,61 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013,2014,2015 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +struct GLnxConsoleRef { + gboolean locked; + gboolean is_tty; +}; + +typedef struct GLnxConsoleRef GLnxConsoleRef; + +gboolean glnx_stdout_is_tty (void); + +void glnx_console_lock (GLnxConsoleRef *ref); + +void glnx_console_text (const char *text); + +void glnx_console_progress_text_percent (const char *text, + guint percentage); + +void glnx_console_progress_n_items (const char *text, + guint current, + guint total); + +void glnx_console_unlock (GLnxConsoleRef *ref); + +guint glnx_console_lines (void); + +guint glnx_console_columns (void); + +static inline void +glnx_console_ref_cleanup (GLnxConsoleRef *p) +{ + if (p->locked) + glnx_console_unlock (p); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxConsoleRef, glnx_console_ref_cleanup) + +G_END_DECLS diff --git a/libglnx/glnx-dirfd.c b/libglnx/glnx-dirfd.c new file mode 100644 index 0000000..6d1e2d2 --- /dev/null +++ b/libglnx/glnx-dirfd.c @@ -0,0 +1,425 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +/** + * glnx_opendirat_with_errno: + * @dfd: File descriptor for origin directory + * @name: Pathname, relative to @dfd + * @follow: Whether or not to follow symbolic links + * + * Use openat() to open a directory, using a standard set of flags. + * This function sets errno. + */ +int +glnx_opendirat_with_errno (int dfd, + const char *path, + gboolean follow) +{ + int flags = O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY; + if (!follow) + flags |= O_NOFOLLOW; + + dfd = glnx_dirfd_canonicalize (dfd); + + return openat (dfd, path, flags); +} + +/** + * glnx_opendirat: + * @dfd: File descriptor for origin directory + * @path: Pathname, relative to @dfd + * @follow: Whether or not to follow symbolic links + * @error: Error + * + * Use openat() to open a directory, using a standard set of flags. + */ +gboolean +glnx_opendirat (int dfd, + const char *path, + gboolean follow, + int *out_fd, + GError **error) +{ + int ret = glnx_opendirat_with_errno (dfd, path, follow); + if (ret == -1) + return glnx_throw_errno_prefix (error, "opendir(%s)", path); + *out_fd = ret; + return TRUE; +} + +struct GLnxRealDirfdIterator +{ + gboolean initialized; + int fd; + DIR *d; +}; +typedef struct GLnxRealDirfdIterator GLnxRealDirfdIterator; + +/** + * glnx_dirfd_iterator_init_at: + * @dfd: File descriptor, may be AT_FDCWD or -1 + * @path: Path, may be relative to @dfd + * @follow: If %TRUE and the last component of @path is a symlink, follow it + * @out_dfd_iter: (out caller-allocates): A directory iterator, will be initialized + * @error: Error + * + * Initialize @out_dfd_iter from @dfd and @path. + */ +gboolean +glnx_dirfd_iterator_init_at (int dfd, + const char *path, + gboolean follow, + GLnxDirFdIterator *out_dfd_iter, + GError **error) +{ + glnx_autofd int fd = -1; + if (!glnx_opendirat (dfd, path, follow, &fd, error)) + return FALSE; + + if (!glnx_dirfd_iterator_init_take_fd (&fd, out_dfd_iter, error)) + return FALSE; + + return TRUE; +} + +/** + * glnx_dirfd_iterator_init_take_fd: + * @dfd: File descriptor - ownership is taken, and the value is set to -1 + * @dfd_iter: A directory iterator + * @error: Error + * + * Steal ownership of @dfd, using it to initialize @dfd_iter for + * iteration. + */ +gboolean +glnx_dirfd_iterator_init_take_fd (int *dfd, + GLnxDirFdIterator *dfd_iter, + GError **error) +{ + GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter; + DIR *d = fdopendir (*dfd); + if (!d) + return glnx_throw_errno_prefix (error, "fdopendir"); + + real_dfd_iter->fd = glnx_steal_fd (dfd); + real_dfd_iter->d = d; + real_dfd_iter->initialized = TRUE; + + return TRUE; +} + +/** + * glnx_dirfd_iterator_next_dent: + * @dfd_iter: A directory iterator + * @out_dent: (out) (transfer none): Pointer to dirent; do not free + * @cancellable: Cancellable + * @error: Error + * + * Read the next value from @dfd_iter, causing @out_dent to be + * updated. If end of stream is reached, @out_dent will be set + * to %NULL, and %TRUE will be returned. + */ +gboolean +glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error) +{ + GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter; + + g_return_val_if_fail (out_dent, FALSE); + g_return_val_if_fail (dfd_iter->initialized, FALSE); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + do + { + errno = 0; + *out_dent = readdir (real_dfd_iter->d); + if (*out_dent == NULL && errno != 0) + return glnx_throw_errno_prefix (error, "readdir"); + } while (*out_dent && + (strcmp ((*out_dent)->d_name, ".") == 0 || + strcmp ((*out_dent)->d_name, "..") == 0)); + + return TRUE; +} + +/** + * glnx_dirfd_iterator_next_dent_ensure_dtype: + * @dfd_iter: A directory iterator + * @out_dent: (out) (transfer none): Pointer to dirent; do not free + * @cancellable: Cancellable + * @error: Error + * + * A variant of @glnx_dirfd_iterator_next_dent, which will ensure the + * `dent->d_type` member is filled in by calling `fstatat` + * automatically if the underlying filesystem type sets `DT_UNKNOWN`. + */ +gboolean +glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (out_dent, FALSE); + + if (!glnx_dirfd_iterator_next_dent (dfd_iter, out_dent, cancellable, error)) + return FALSE; + + struct dirent *ret_dent = *out_dent; + if (ret_dent) + { + + if (ret_dent->d_type == DT_UNKNOWN) + { + struct stat stbuf; + if (!glnx_fstatat (dfd_iter->fd, ret_dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + ret_dent->d_type = IFTODT (stbuf.st_mode); + } + } + + return TRUE; +} + +/** + * glnx_dirfd_iterator_clear: + * @dfd_iter: Iterator, will be de-initialized + * + * Unset @dfd_iter, freeing any resources. If @dfd_iter is not + * initialized, do nothing. + */ +void +glnx_dirfd_iterator_clear (GLnxDirFdIterator *dfd_iter) +{ + GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter; + /* fd is owned by dfd_iter */ + if (!real_dfd_iter->initialized) + return; + (void) closedir (real_dfd_iter->d); + real_dfd_iter->initialized = FALSE; +} + +/** + * glnx_fdrel_abspath: + * @dfd: Directory fd + * @path: Path + * + * Turn a fd-relative pair into something that can be used for legacy + * APIs expecting absolute paths. + * + * This is Linux specific, and only valid inside this process (unless + * you set up the child process to have the exact same fd number, but + * don't try that). + */ +char * +glnx_fdrel_abspath (int dfd, + const char *path) +{ + dfd = glnx_dirfd_canonicalize (dfd); + if (dfd == AT_FDCWD) + return g_strdup (path); + return g_strdup_printf ("/proc/self/fd/%d/%s", dfd, path); +} + +/** + * glnx_gen_temp_name: + * @tmpl: (type filename): template directory name, the last 6 characters will be replaced + * + * Replace the last 6 characters of @tmpl with random ASCII. You must + * use this in combination with a mechanism to ensure race-free file + * creation such as `O_EXCL`. + */ +void +glnx_gen_temp_name (gchar *tmpl) +{ + g_return_if_fail (tmpl != NULL); + const size_t len = strlen (tmpl); + g_return_if_fail (len >= 6); + + static const char letters[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + static const int NLETTERS = sizeof (letters) - 1; + + char *XXXXXX = tmpl + (len - 6); + for (int i = 0; i < 6; i++) + XXXXXX[i] = letters[g_random_int_range(0, NLETTERS)]; +} + +/** + * glnx_mkdtempat: + * @dfd: Directory fd + * @tmpl: (type filename): Initial template directory name, last 6 characters will be replaced + * @mode: permissions with which to create the temporary directory + * @out_tmpdir: (out caller-allocates): Initialized tempdir structure + * @error: Error + * + * Somewhat similar to g_mkdtemp_full(), but fd-relative, and returns a + * structure that uses autocleanups. Note that the supplied @dfd lifetime + * must match or exceed that of @out_tmpdir in order to remove the directory. + */ +gboolean +glnx_mkdtempat (int dfd, const char *tmpl, int mode, + GLnxTmpDir *out_tmpdir, GError **error) +{ + g_return_val_if_fail (tmpl != NULL, FALSE); + g_return_val_if_fail (out_tmpdir != NULL, FALSE); + g_return_val_if_fail (!out_tmpdir->initialized, FALSE); + + dfd = glnx_dirfd_canonicalize (dfd); + + g_autofree char *path = g_strdup (tmpl); + for (int count = 0; count < 100; count++) + { + glnx_gen_temp_name (path); + + /* Ideally we could use openat(O_DIRECTORY | O_CREAT | O_EXCL) here + * to create and open the directory atomically, but that’s not supported by + * current kernel versions: http://www.openwall.com/lists/oss-security/2014/11/26/14 + * (Tested on kernel 4.10.10-200.fc25.x86_64). For the moment, accept a + * TOCTTOU race here. */ + if (mkdirat (dfd, path, mode) == -1) + { + if (errno == EEXIST) + continue; + + /* Any other error will apply also to other names we might + * try, and there are 2^32 or so of them, so give up now. + */ + return glnx_throw_errno_prefix (error, "mkdirat"); + } + + /* And open it */ + glnx_autofd int ret_dfd = -1; + if (!glnx_opendirat (dfd, path, FALSE, &ret_dfd, error)) + { + /* If we fail to open, let's try to clean up */ + (void)unlinkat (dfd, path, AT_REMOVEDIR); + return FALSE; + } + + /* Return the initialized directory struct */ + out_tmpdir->initialized = TRUE; + out_tmpdir->src_dfd = dfd; /* referenced; see above docs */ + out_tmpdir->fd = glnx_steal_fd (&ret_dfd); + out_tmpdir->path = g_steal_pointer (&path); + return TRUE; + } + + /* Failure */ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "glnx_mkdtempat ran out of combinations to try"); + return FALSE; +} + +/** + * glnx_mkdtemp: + * @tmpl: (type filename): Source template directory name, last 6 characters will be replaced + * @mode: permissions to create the temporary directory with + * @out_tmpdir: (out caller-allocates): Return location for tmpdir data + * @error: Return location for a #GError, or %NULL + * + * Similar to glnx_mkdtempat(), but will use g_get_tmp_dir() as the parent + * directory to @tmpl. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +gboolean +glnx_mkdtemp (const gchar *tmpl, + int mode, + GLnxTmpDir *out_tmpdir, + GError **error) +{ + g_autofree char *path = g_build_filename (g_get_tmp_dir (), tmpl, NULL); + return glnx_mkdtempat (AT_FDCWD, path, mode, + out_tmpdir, error); +} + +static gboolean +_glnx_tmpdir_free (GLnxTmpDir *tmpd, + gboolean delete_dir, + GCancellable *cancellable, + GError **error) +{ + /* Support being passed NULL so we work nicely in a GPtrArray */ + if (!(tmpd && tmpd->initialized)) + return TRUE; + g_assert_cmpint (tmpd->fd, !=, -1); + glnx_close_fd (&tmpd->fd); + g_assert (tmpd->path); + g_assert_cmpint (tmpd->src_dfd, !=, -1); + g_autofree char *path = tmpd->path; /* Take ownership */ + tmpd->initialized = FALSE; + if (delete_dir) + { + if (!glnx_shutil_rm_rf_at (tmpd->src_dfd, path, cancellable, error)) + return FALSE; + } + return TRUE; +} + +/** + * glnx_tmpdir_delete: + * @tmpf: Temporary dir + * @cancellable: Cancellable + * @error: Error + * + * Deallocate a tmpdir, closing the fd and recursively deleting the path. This + * is normally called indirectly via glnx_tmpdir_cleanup() by the autocleanup + * attribute, but you can also invoke this directly. + * + * If an error occurs while deleting the filesystem path, @tmpf will still have + * been deallocated and should not be reused. + * + * See also `glnx_tmpdir_unset` to avoid deleting the path. + */ +gboolean +glnx_tmpdir_delete (GLnxTmpDir *tmpf, GCancellable *cancellable, GError **error) +{ + return _glnx_tmpdir_free (tmpf, TRUE, cancellable, error); +} + +/** + * glnx_tmpdir_unset: + * @tmpf: Temporary dir + * @cancellable: Cancellable + * @error: Error + * + * Deallocate a tmpdir, but do not delete the filesystem path. See also + * `glnx_tmpdir_delete()`. + */ +void +glnx_tmpdir_unset (GLnxTmpDir *tmpf) +{ + (void) _glnx_tmpdir_free (tmpf, FALSE, NULL, NULL); +} diff --git a/libglnx/glnx-dirfd.h b/libglnx/glnx-dirfd.h new file mode 100644 index 0000000..0046ac8 --- /dev/null +++ b/libglnx/glnx-dirfd.h @@ -0,0 +1,137 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +/** + * glnx_dirfd_canonicalize: + * @fd: A directory file descriptor + * + * It's often convenient in programs to use `-1` for "unassigned fd", + * and also because gobject-introspection doesn't support `AT_FDCWD`, + * libglnx honors `-1` to mean `AT_FDCWD`. This small inline function + * canonicalizes `-1 -> AT_FDCWD`. + */ +static inline int +glnx_dirfd_canonicalize (int fd) +{ + if (fd == -1) + return AT_FDCWD; + return fd; +} + +struct GLnxDirFdIterator { + gboolean initialized; + int fd; + gpointer padding_data[4]; +}; + +typedef struct GLnxDirFdIterator GLnxDirFdIterator; +gboolean glnx_dirfd_iterator_init_at (int dfd, const char *path, + gboolean follow, + GLnxDirFdIterator *dfd_iter, GError **error); +gboolean glnx_dirfd_iterator_init_take_fd (int *dfd, GLnxDirFdIterator *dfd_iter, GError **error); +gboolean glnx_dirfd_iterator_next_dent (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error); +gboolean glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator *dfd_iter, + struct dirent **out_dent, + GCancellable *cancellable, + GError **error); +void glnx_dirfd_iterator_clear (GLnxDirFdIterator *dfd_iter); + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxDirFdIterator, glnx_dirfd_iterator_clear) + +int glnx_opendirat_with_errno (int dfd, + const char *path, + gboolean follow); + +gboolean glnx_opendirat (int dfd, + const char *path, + gboolean follow, + int *out_fd, + GError **error); + +char *glnx_fdrel_abspath (int dfd, + const char *path); + +void glnx_gen_temp_name (gchar *tmpl); + +/** + * glnx_ensure_dir: + * @dfd: directory fd + * @path: Directory path + * @mode: Mode + * @error: Return location for a #GError, or %NULL + * + * Wrapper around mkdirat() which adds #GError support, ensures that + * it retries on %EINTR, and also ignores `EEXIST`. + * + * See also `glnx_shutil_mkdir_p_at()` for recursive handling. + * + * Returns: %TRUE on success, %FALSE otherwise + */ +static inline gboolean +glnx_ensure_dir (int dfd, + const char *path, + mode_t mode, + GError **error) +{ + if (TEMP_FAILURE_RETRY (mkdirat (dfd, path, mode)) != 0) + { + if (G_UNLIKELY (errno != EEXIST)) + return glnx_throw_errno_prefix (error, "mkdirat(%s)", path); + } + return TRUE; +} + +typedef struct { + gboolean initialized; + int src_dfd; + int fd; + char *path; +} GLnxTmpDir; +gboolean glnx_tmpdir_delete (GLnxTmpDir *tmpf, GCancellable *cancellable, GError **error); +void glnx_tmpdir_unset (GLnxTmpDir *tmpf); +static inline void +glnx_tmpdir_cleanup (GLnxTmpDir *tmpf) +{ + (void)glnx_tmpdir_delete (tmpf, NULL, NULL); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxTmpDir, glnx_tmpdir_cleanup) + +gboolean glnx_mkdtempat (int dfd, const char *tmpl, int mode, + GLnxTmpDir *out_tmpdir, GError **error); + +gboolean glnx_mkdtemp (const char *tmpl, int mode, + GLnxTmpDir *out_tmpdir, GError **error); + +G_END_DECLS diff --git a/libglnx/glnx-errors.c b/libglnx/glnx-errors.c new file mode 100644 index 0000000..f350f30 --- /dev/null +++ b/libglnx/glnx-errors.c @@ -0,0 +1,131 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +/* Set @error with G_IO_ERROR/G_IO_ERROR_FAILED. + * + * This function returns %FALSE so it can be used conveniently in a single + * statement: + * + * ``` + * if (strcmp (foo, "somevalue") != 0) + * return glnx_throw (error, "key must be somevalue, not '%s'", foo); + * ``` + */ +gboolean +glnx_throw (GError **error, + const char *fmt, + ...) +{ + if (error == NULL) + return FALSE; + + va_list args; + va_start (args, fmt); + GError *new = g_error_new_valist (G_IO_ERROR, G_IO_ERROR_FAILED, fmt, args); + va_end (args); + g_propagate_error (error, g_steal_pointer (&new)); + return FALSE; +} + +void +glnx_real_set_prefix_error_va (GError *error, + const char *format, + va_list args) +{ + if (error == NULL) + return; + + g_autofree char *old_msg = g_steal_pointer (&error->message); + g_autoptr(GString) buf = g_string_new (""); + g_string_append_vprintf (buf, format, args); + g_string_append (buf, ": "); + g_string_append (buf, old_msg); + error->message = g_string_free (g_steal_pointer (&buf), FALSE); +} + +/* Prepend to @error's message by `$prefix: ` where `$prefix` is computed via + * printf @fmt. Returns %FALSE so it can be used conveniently in a single + * statement: + * + * ``` + * if (!function_that_fails (s, error)) + * return glnx_throw_prefix (error, "while handling '%s'", s); + * ``` + * */ +gboolean +glnx_prefix_error (GError **error, + const char *fmt, + ...) +{ + if (error == NULL) + return FALSE; + + va_list args; + va_start (args, fmt); + glnx_real_set_prefix_error_va (*error, fmt, args); + va_end (args); + return FALSE; +} + +void +glnx_real_set_prefix_error_from_errno_va (GError **error, + gint errsv, + const char *format, + va_list args) +{ + if (!error) + return; + + g_set_error_literal (error, + G_IO_ERROR, + g_io_error_from_errno (errsv), + g_strerror (errsv)); + glnx_real_set_prefix_error_va (*error, format, args); +} + +/* Set @error using the value of `$prefix: g_strerror (errno)` where `$prefix` + * is computed via printf @fmt. + * + * This function returns %FALSE so it can be used conveniently in a single + * statement: + * + * ``` + * return glnx_throw_errno_prefix (error, "unlinking %s", pathname); + * ``` + */ +gboolean +glnx_throw_errno_prefix (GError **error, + const char *fmt, + ...) +{ + int errsv = errno; + va_list args; + va_start (args, fmt); + glnx_real_set_prefix_error_from_errno_va (error, errsv, fmt, args); + va_end (args); + /* See comment in glnx_throw_errno() about preserving errno */ + errno = errsv; + return FALSE; +} diff --git a/libglnx/glnx-errors.h b/libglnx/glnx-errors.h new file mode 100644 index 0000000..cbe74a6 --- /dev/null +++ b/libglnx/glnx-errors.h @@ -0,0 +1,134 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +gboolean glnx_throw (GError **error, const char *fmt, ...) G_GNUC_PRINTF (2,3); + +/* Like `glnx_throw ()`, but returns %NULL. */ +#define glnx_null_throw(error, args...) \ + ({glnx_throw (error, args); NULL;}) + +/* Implementation detail of glnx_throw_prefix() */ +void glnx_real_set_prefix_error_va (GError *error, + const char *format, + va_list args) G_GNUC_PRINTF (2,0); + +gboolean glnx_prefix_error (GError **error, const char *fmt, ...) G_GNUC_PRINTF (2,3); + +/* Like `glnx_prefix_error ()`, but returns %NULL. */ +#define glnx_prefix_error_null(error, args...) \ + ({glnx_prefix_error (error, args); NULL;}) + +/** + * GLNX_AUTO_PREFIX_ERROR: + * + * An autocleanup-based macro to automatically call `g_prefix_error()` (also with a colon+space `: `) + * when it goes out of scope. This is useful when one wants error strings built up by the callee + * function, not all callers. + * + * ``` + * gboolean start_http_request (..., GError **error) + * { + * GLNX_AUTO_PREFIX_ERROR ("HTTP request", error) + * + * if (!libhttp_request_start (..., error)) + * return FALSE; + * ... + * return TRUE; + * ``` + */ +typedef struct { + const char *prefix; + GError **error; +} GLnxAutoErrorPrefix; +static inline void +glnx_cleanup_auto_prefix_error (GLnxAutoErrorPrefix *prefix) +{ + if (prefix->error && *(prefix->error)) + g_prefix_error (prefix->error, "%s: ", prefix->prefix); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxAutoErrorPrefix, glnx_cleanup_auto_prefix_error) +#define GLNX_AUTO_PREFIX_ERROR(text, error) \ + G_GNUC_UNUSED g_auto(GLnxAutoErrorPrefix) _GLNX_MAKE_ANONYMOUS(_glnxautoprefixerror_) = { text, error } + +/* Set @error using the value of `g_strerror (errno)`. + * + * This function returns %FALSE so it can be used conveniently in a single + * statement: + * + * ``` + * if (unlinkat (fd, somepathname) < 0) + * return glnx_throw_errno (error); + * ``` + */ +static inline gboolean +glnx_throw_errno (GError **error) +{ + /* Save the value of errno, in case one of the + * intermediate function calls happens to set it. + */ + int errsv = errno; + g_set_error_literal (error, G_IO_ERROR, + g_io_error_from_errno (errsv), + g_strerror (errsv)); + /* We also restore the value of errno, since that's + * what was done in a long-ago libgsystem commit + * https://git.gnome.org/browse/libgsystem/commit/?id=ed106741f7a0596dc8b960b31fdae671d31d666d + * but I certainly can't remember now why I did that. + */ + errno = errsv; + return FALSE; +} + +/* Like glnx_throw_errno(), but yields a NULL pointer. */ +#define glnx_null_throw_errno(error) \ + ({glnx_throw_errno (error); NULL;}) + +/* Implementation detail of glnx_throw_errno_prefix() */ +void glnx_real_set_prefix_error_from_errno_va (GError **error, + gint errsv, + const char *format, + va_list args) G_GNUC_PRINTF (3,0); + +gboolean glnx_throw_errno_prefix (GError **error, const char *fmt, ...) G_GNUC_PRINTF (2,3); + +/* Like glnx_throw_errno_prefix(), but yields a NULL pointer. */ +#define glnx_null_throw_errno_prefix(error, args...) \ + ({glnx_throw_errno_prefix (error, args); NULL;}) + +/* BEGIN LEGACY APIS */ + +#define glnx_set_error_from_errno(error) \ + do { \ + glnx_throw_errno (error); \ + } while (0); + +#define glnx_set_prefix_error_from_errno(error, format, args...) \ + do { \ + glnx_throw_errno_prefix (error, format, args); \ + } while (0); + +G_END_DECLS diff --git a/libglnx/glnx-fdio.c b/libglnx/glnx-fdio.c new file mode 100644 index 0000000..e537a9b --- /dev/null +++ b/libglnx/glnx-fdio.c @@ -0,0 +1,1161 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * Portions derived from systemd: + * Copyright 2010 Lennart Poettering + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* The standardized version of BTRFS_IOC_CLONE */ +#ifndef FICLONE +#define FICLONE _IOW(0x94, 9, int) +#endif + +/* Returns the number of chars needed to format variables of the + * specified type as a decimal string. Adds in extra space for a + * negative '-' prefix (hence works correctly on signed + * types). Includes space for the trailing NUL. */ +#define DECIMAL_STR_MAX(type) \ + (2+(sizeof(type) <= 1 ? 3 : \ + sizeof(type) <= 2 ? 5 : \ + sizeof(type) <= 4 ? 10 : \ + sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) + +gboolean +glnx_stdio_file_flush (FILE *f, GError **error) +{ + if (fflush (f) != 0) + return glnx_throw_errno_prefix (error, "fflush"); + if (ferror (f) != 0) + return glnx_throw_errno_prefix (error, "ferror"); + return TRUE; +} + +/* An implementation of renameat2(..., RENAME_NOREPLACE) + * with fallback to a non-atomic version. + */ +int +glnx_renameat2_noreplace (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath) +{ +#ifndef ENABLE_WRPSEUDO_COMPAT + if (renameat2 (olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) < 0) + { + if (G_IN_SET(errno, EINVAL, ENOSYS)) + { + /* Fall through */ + } + else + { + return -1; + } + } + else + return TRUE; +#endif + + if (linkat (olddirfd, oldpath, newdirfd, newpath, 0) < 0) + return -1; + + if (unlinkat (olddirfd, oldpath, 0) < 0) + return -1; + + return 0; +} + +static gboolean +rename_file_noreplace_at (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, + gboolean ignore_eexist, + GError **error) +{ + if (glnx_renameat2_noreplace (olddirfd, oldpath, + newdirfd, newpath) < 0) + { + if (errno == EEXIST && ignore_eexist) + { + (void) unlinkat (olddirfd, oldpath, 0); + return TRUE; + } + else + return glnx_throw_errno_prefix (error, "renameat"); + } + return TRUE; +} + +/* An implementation of renameat2(..., RENAME_EXCHANGE) + * with fallback to a non-atomic version. + */ +int +glnx_renameat2_exchange (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath) +{ +#ifndef ENABLE_WRPSEUDO_COMPAT + if (renameat2 (olddirfd, oldpath, newdirfd, newpath, RENAME_EXCHANGE) == 0) + return 0; + else + { + if (G_IN_SET(errno, ENOSYS, EINVAL)) + { + /* Fall through */ + } + else + { + return -1; + } + } +#endif + + /* Fallback */ + { char *old_tmp_name_buf = glnx_strjoina (oldpath, ".XXXXXX"); + /* This obviously isn't race-free, but doing better gets tricky, since if + * we're here the kernel isn't likely to support RENAME_NOREPLACE either. + * Anyways, upgrade the kernel. Failing that, avoid use of this function in + * shared subdirectories like /tmp. + */ + glnx_gen_temp_name (old_tmp_name_buf); + const char *old_tmp_name = old_tmp_name_buf; + + /* Move old out of the way */ + if (renameat (olddirfd, oldpath, olddirfd, old_tmp_name) < 0) + return -1; + /* Now move new into its place */ + if (renameat (newdirfd, newpath, olddirfd, oldpath) < 0) + return -1; + /* And finally old(tmp) into new */ + if (renameat (olddirfd, old_tmp_name, newdirfd, newpath) < 0) + return -1; + } + return 0; +} + +/* Deallocate a tmpfile, closing the fd and deleting the path, if any. This is + * normally called by default by the autocleanup attribute, but you can also + * invoke this directly. + */ +void +glnx_tmpfile_clear (GLnxTmpfile *tmpf) +{ + /* Support being passed NULL so we work nicely in a GPtrArray */ + if (!tmpf) + return; + if (!tmpf->initialized) + return; + glnx_close_fd (&tmpf->fd); + /* If ->path is set, we're likely aborting due to an error. Clean it up */ + if (tmpf->path) + { + (void) unlinkat (tmpf->src_dfd, tmpf->path, 0); + g_free (tmpf->path); + } + tmpf->initialized = FALSE; +} + +static gboolean +open_tmpfile_core (int dfd, const char *subpath, + int flags, + GLnxTmpfile *out_tmpf, + GError **error) +{ + /* Picked this to match mkstemp() */ + const guint mode = 0600; + + dfd = glnx_dirfd_canonicalize (dfd); + + /* Creates a temporary file, that shall be renamed to "target" + * later. If possible, this uses O_TMPFILE – in which case + * "ret_path" will be returned as NULL. If not possible a the + * tempoary path name used is returned in "ret_path". Use + * link_tmpfile() below to rename the result after writing the file + * in full. */ +#if defined(O_TMPFILE) && !defined(DISABLE_OTMPFILE) && !defined(ENABLE_WRPSEUDO_COMPAT) + { + glnx_autofd int fd = openat (dfd, subpath, O_TMPFILE|flags, mode); + if (fd == -1 && !(G_IN_SET(errno, ENOSYS, EISDIR, EOPNOTSUPP))) + return glnx_throw_errno_prefix (error, "open(O_TMPFILE)"); + if (fd != -1) + { + /* Workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17523 + * See also https://github.com/ostreedev/ostree/issues/991 + */ + if (fchmod (fd, mode) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + out_tmpf->initialized = TRUE; + out_tmpf->src_dfd = dfd; /* Copied; caller must keep open */ + out_tmpf->fd = glnx_steal_fd (&fd); + out_tmpf->path = NULL; + return TRUE; + } + } + /* Fallthrough */ +#endif + + const guint count_max = 100; + { g_autofree char *tmp = g_strconcat (subpath, "/tmp.XXXXXX", NULL); + + for (int count = 0; count < count_max; count++) + { + glnx_gen_temp_name (tmp); + + glnx_autofd int fd = openat (dfd, tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, mode); + if (fd < 0) + { + if (errno == EEXIST) + continue; + else + return glnx_throw_errno_prefix (error, "Creating temp file"); + } + else + { + out_tmpf->initialized = TRUE; + out_tmpf->src_dfd = dfd; /* Copied; caller must keep open */ + out_tmpf->fd = glnx_steal_fd (&fd); + out_tmpf->path = g_steal_pointer (&tmp); + return TRUE; + } + } + } + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "Exhausted %u attempts to create temporary file", count_max); + return FALSE; +} + +/* Allocate a temporary file, using Linux O_TMPFILE if available. The file mode + * will be 0600. + * + * The result will be stored in @out_tmpf, which is caller allocated + * so you can store it on the stack in common scenarios. + * + * The directory fd @dfd must live at least as long as the output @out_tmpf. + */ +gboolean +glnx_open_tmpfile_linkable_at (int dfd, + const char *subpath, + int flags, + GLnxTmpfile *out_tmpf, + GError **error) +{ + /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE; + * it's used for glnx_open_anonymous_tmpfile(). + */ + g_return_val_if_fail ((flags & O_EXCL) == 0, FALSE); + + return open_tmpfile_core (dfd, subpath, flags, out_tmpf, error); +} + + +/* A variant of `glnx_open_tmpfile_linkable_at()` which doesn't support linking. + * Useful for true temporary storage. The fd will be allocated in the specified + * directory. + */ +gboolean +glnx_open_anonymous_tmpfile_full (int flags, + const char *dir, + GLnxTmpfile *out_tmpf, + GError **error) +{ + /* Add in O_EXCL */ + if (!open_tmpfile_core (AT_FDCWD, dir, flags | O_EXCL, out_tmpf, error)) + return FALSE; + if (out_tmpf->path) + { + (void) unlinkat (out_tmpf->src_dfd, out_tmpf->path, 0); + g_clear_pointer (&out_tmpf->path, g_free); + } + out_tmpf->anonymous = TRUE; + out_tmpf->src_dfd = -1; + return TRUE; +} + +/* A variant of `glnx_open_tmpfile_linkable_at()` which doesn't support linking. + * Useful for true temporary storage. The fd will be allocated in /var/tmp to + * ensure maximum storage space. + * + * If you need the file on a specific filesystem use glnx_open_anonymous_tmpfile_full() + * which lets you pass a directory. + */ +gboolean +glnx_open_anonymous_tmpfile (int flags, + GLnxTmpfile *out_tmpf, + GError **error) +{ + return glnx_open_anonymous_tmpfile_full (flags, "/var/tmp", out_tmpf, error); +} + +/* Use this after calling glnx_open_tmpfile_linkable_at() to give + * the file its final name (link into place). + */ +gboolean +glnx_link_tmpfile_at (GLnxTmpfile *tmpf, + GLnxLinkTmpfileReplaceMode mode, + int target_dfd, + const char *target, + GError **error) +{ + const gboolean replace = (mode == GLNX_LINK_TMPFILE_REPLACE); + const gboolean ignore_eexist = (mode == GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST); + + g_return_val_if_fail (!tmpf->anonymous, FALSE); + g_return_val_if_fail (tmpf->fd >= 0, FALSE); + g_return_val_if_fail (tmpf->src_dfd == AT_FDCWD || tmpf->src_dfd >= 0, FALSE); + + /* Unlike the original systemd code, this function also supports + * replacing existing files. + */ + + /* We have `tmpfile_path` for old systems without O_TMPFILE. */ + if (tmpf->path) + { + if (replace) + { + /* We have a regular tempfile, we're overwriting - this is a + * simple renameat(). + */ + if (renameat (tmpf->src_dfd, tmpf->path, target_dfd, target) < 0) + return glnx_throw_errno_prefix (error, "renameat"); + } + else + { + /* We need to use renameat2(..., NOREPLACE) or emulate it */ + if (!rename_file_noreplace_at (tmpf->src_dfd, tmpf->path, target_dfd, target, + ignore_eexist, + error)) + return FALSE; + } + /* Now, clear the pointer so we don't try to unlink it */ + g_clear_pointer (&tmpf->path, g_free); + } + else + { + /* This case we have O_TMPFILE, so our reference to it is via /proc/self/fd */ + char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(tmpf->fd) + 1]; + snprintf (proc_fd_path, sizeof (proc_fd_path), "/proc/self/fd/%i", tmpf->fd); + + if (replace) + { + /* In this case, we had our temp file atomically hidden, but now + * we need to make it visible in the FS so we can do a rename. + * Ideally, linkat() would gain AT_REPLACE or so. + */ + /* TODO - avoid double alloca, we can just alloca a copy of + * the pathname plus space for tmp.XXXXX */ + char *dnbuf = strdupa (target); + const char *dn = dirname (dnbuf); + char *tmpname_buf = glnx_strjoina (dn, "/tmp.XXXXXX"); + + const guint count_max = 100; + guint count; + for (count = 0; count < count_max; count++) + { + glnx_gen_temp_name (tmpname_buf); + + if (linkat (AT_FDCWD, proc_fd_path, target_dfd, tmpname_buf, AT_SYMLINK_FOLLOW) < 0) + { + if (errno == EEXIST) + continue; + else + return glnx_throw_errno_prefix (error, "linkat"); + } + else + break; + } + if (count == count_max) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "Exhausted %u attempts to create temporary file", count); + return FALSE; + } + if (!glnx_renameat (target_dfd, tmpname_buf, target_dfd, target, error)) + { + /* This is currently the only case where we need to have + * a cleanup unlinkat() still with O_TMPFILE. + */ + (void) unlinkat (target_dfd, tmpname_buf, 0); + return FALSE; + } + } + else + { + if (linkat (AT_FDCWD, proc_fd_path, target_dfd, target, AT_SYMLINK_FOLLOW) < 0) + { + if (errno == EEXIST && mode == GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST) + ; + else + return glnx_throw_errno_prefix (error, "linkat"); + } + } + + } + return TRUE; +} + +/* glnx_tmpfile_reopen_rdonly: + * @tmpf: tmpfile + * @error: Error + * + * Give up write access to the file descriptior. One use + * case for this is fs-verity, which requires a read-only fd. + * It could also be useful to allocate an anonymous tmpfile + * write some sort of caching/indexing data to it, then reopen it + * read-only thereafter. + **/ +gboolean +glnx_tmpfile_reopen_rdonly (GLnxTmpfile *tmpf, + GError **error) +{ + g_return_val_if_fail (tmpf->fd >= 0, FALSE); + g_return_val_if_fail (tmpf->src_dfd == AT_FDCWD || tmpf->src_dfd >= 0, FALSE); + + glnx_fd_close int rdonly_fd = -1; + + if (tmpf->path) + { + if (!glnx_openat_rdonly (tmpf->src_dfd, tmpf->path, FALSE, &rdonly_fd, error)) + return FALSE; + } + else + { + /* This case we have O_TMPFILE, so our reference to it is via /proc/self/fd */ + char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(tmpf->fd) + 1]; + snprintf (proc_fd_path, sizeof (proc_fd_path), "/proc/self/fd/%i", tmpf->fd); + + if (!glnx_openat_rdonly (AT_FDCWD, proc_fd_path, TRUE, &rdonly_fd, error)) + return FALSE; + } + + glnx_close_fd (&tmpf->fd); + tmpf->fd = glnx_steal_fd (&rdonly_fd); + return TRUE; +} + +/** + * glnx_openat_rdonly: + * @dfd: File descriptor for origin directory + * @path: Pathname, relative to @dfd + * @follow: Whether or not to follow symbolic links in the final component + * @out_fd: (out): File descriptor + * @error: Error + * + * Use openat() to open a file, with flags `O_RDONLY | O_CLOEXEC | O_NOCTTY`. + * Like the other libglnx wrappers, will use `TEMP_FAILURE_RETRY` and + * also includes @path in @error in case of failure. + */ +gboolean +glnx_openat_rdonly (int dfd, + const char *path, + gboolean follow, + int *out_fd, + GError **error) +{ + int flags = O_RDONLY | O_CLOEXEC | O_NOCTTY; + if (!follow) + flags |= O_NOFOLLOW; + int fd = TEMP_FAILURE_RETRY (openat (dfd, path, flags)); + if (fd == -1) + return glnx_throw_errno_prefix (error, "openat(%s)", path); + *out_fd = fd; + return TRUE; +} + +static guint8* +glnx_fd_readall_malloc (int fd, + gsize *out_len, + gboolean nul_terminate, + GCancellable *cancellable, + GError **error) +{ + const guint maxreadlen = 4096; + + struct stat stbuf; + if (!glnx_fstat (fd, &stbuf, error)) + return FALSE; + + gsize buf_allocated; + if (S_ISREG (stbuf.st_mode) && stbuf.st_size > 0) + buf_allocated = stbuf.st_size; + else + buf_allocated = 16; + + g_autofree guint8* buf = g_malloc (buf_allocated); + + gsize buf_size = 0; + while (TRUE) + { + gsize readlen = MIN (buf_allocated - buf_size, maxreadlen); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + gssize bytes_read; + do + bytes_read = read (fd, buf + buf_size, readlen); + while (G_UNLIKELY (bytes_read == -1 && errno == EINTR)); + if (G_UNLIKELY (bytes_read == -1)) + return glnx_null_throw_errno (error); + if (bytes_read == 0) + break; + + buf_size += bytes_read; + if (buf_allocated - buf_size < maxreadlen) + buf = g_realloc (buf, buf_allocated *= 2); + } + + if (nul_terminate) + { + if (buf_allocated - buf_size == 0) + buf = g_realloc (buf, buf_allocated + 1); + buf[buf_size] = '\0'; + } + + *out_len = buf_size; + return g_steal_pointer (&buf); +} + +/** + * glnx_fd_readall_bytes: + * @fd: A file descriptor + * @cancellable: Cancellable: + * @error: Error + * + * Read all data from file descriptor @fd into a #GBytes. It's + * recommended to only use this for small files. + * + * Returns: (transfer full): A newly allocated #GBytes + */ +GBytes * +glnx_fd_readall_bytes (int fd, + GCancellable *cancellable, + GError **error) +{ + gsize len; + guint8 *buf = glnx_fd_readall_malloc (fd, &len, FALSE, cancellable, error); + if (!buf) + return NULL; + return g_bytes_new_take (buf, len); +} + +/** + * glnx_fd_readall_utf8: + * @fd: A file descriptor + * @out_len: (out): Returned length + * @cancellable: Cancellable: + * @error: Error + * + * Read all data from file descriptor @fd, validating + * the result as UTF-8. + * + * Returns: (transfer full): A string validated as UTF-8, or %NULL on error. + */ +char * +glnx_fd_readall_utf8 (int fd, + gsize *out_len, + GCancellable *cancellable, + GError **error) +{ + gsize len; + g_autofree guint8 *buf = glnx_fd_readall_malloc (fd, &len, TRUE, cancellable, error); + if (!buf) + return FALSE; + + if (!g_utf8_validate ((char*)buf, len, NULL)) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "Invalid UTF-8"); + return FALSE; + } + + if (out_len) + *out_len = len; + return (char*)g_steal_pointer (&buf); +} + +/** + * glnx_file_get_contents_utf8_at: + * @dfd: Directory file descriptor + * @subpath: Path relative to @dfd + * @out_len: (out) (allow-none): Optional length + * @cancellable: Cancellable + * @error: Error + * + * Read the entire contents of the file referred + * to by @dfd and @subpath, validate the result as UTF-8. + * The length is optionally stored in @out_len. + * + * Returns: (transfer full): UTF-8 validated text, or %NULL on error + */ +char * +glnx_file_get_contents_utf8_at (int dfd, + const char *subpath, + gsize *out_len, + GCancellable *cancellable, + GError **error) +{ + dfd = glnx_dirfd_canonicalize (dfd); + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd, subpath, TRUE, &fd, error)) + return NULL; + + gsize len; + g_autofree char *buf = glnx_fd_readall_utf8 (fd, &len, cancellable, error); + if (G_UNLIKELY(!buf)) + return FALSE; + + if (out_len) + *out_len = len; + return g_steal_pointer (&buf); +} + +/** + * glnx_readlinkat_malloc: + * @dfd: Directory file descriptor + * @subpath: Subpath + * @cancellable: Cancellable + * @error: Error + * + * Read the value of a symlink into a dynamically + * allocated buffer. + */ +char * +glnx_readlinkat_malloc (int dfd, + const char *subpath, + GCancellable *cancellable, + GError **error) +{ + dfd = glnx_dirfd_canonicalize (dfd); + + size_t l = 100; + for (;;) + { + g_autofree char *c = g_malloc (l); + ssize_t n = TEMP_FAILURE_RETRY (readlinkat (dfd, subpath, c, l-1)); + if (n < 0) + return glnx_null_throw_errno_prefix (error, "readlinkat"); + + if ((size_t) n < l-1) + { + c[n] = 0; + return g_steal_pointer (&c); + } + + l *= 2; + } + + g_assert_not_reached (); +} + +static gboolean +copy_symlink_at (int src_dfd, + const char *src_subpath, + const struct stat *src_stbuf, + int dest_dfd, + const char *dest_subpath, + GLnxFileCopyFlags copyflags, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *buf = glnx_readlinkat_malloc (src_dfd, src_subpath, cancellable, error); + if (!buf) + return FALSE; + + if (TEMP_FAILURE_RETRY (symlinkat (buf, dest_dfd, dest_subpath)) != 0) + return glnx_throw_errno_prefix (error, "symlinkat"); + + if (!(copyflags & GLNX_FILE_COPY_NOXATTRS)) + { + g_autoptr(GVariant) xattrs = NULL; + + if (!glnx_dfd_name_get_all_xattrs (src_dfd, src_subpath, &xattrs, + cancellable, error)) + return FALSE; + + if (!glnx_dfd_name_set_all_xattrs (dest_dfd, dest_subpath, xattrs, + cancellable, error)) + return FALSE; + } + + if (TEMP_FAILURE_RETRY (fchownat (dest_dfd, dest_subpath, + src_stbuf->st_uid, src_stbuf->st_gid, + AT_SYMLINK_NOFOLLOW)) != 0) + return glnx_throw_errno_prefix (error, "fchownat"); + + return TRUE; +} + +#define COPY_BUFFER_SIZE (16*1024) + +/* Most of the code below is from systemd, but has been reindented to GNU style, + * and changed to use POSIX error conventions (return -1, set errno) to more + * conveniently fit in with the rest of libglnx. + */ + +/* Like write(), but loop until @nbytes are written, or an error + * occurs. + * + * On error, -1 is returned an @errno is set. NOTE: This is an + * API change from previous versions of this function. + */ +int +glnx_loop_write(int fd, const void *buf, size_t nbytes) +{ + g_return_val_if_fail (fd >= 0, -1); + g_return_val_if_fail (buf, -1); + + errno = 0; + + const uint8_t *p = buf; + while (nbytes > 0) + { + ssize_t k = write(fd, p, nbytes); + if (k < 0) + { + if (errno == EINTR) + continue; + + return -1; + } + + if (k == 0) /* Can't really happen */ + { + errno = EIO; + return -1; + } + + p += k; + nbytes -= k; + } + + return 0; +} + +/* Read from @fdf until EOF, writing to @fdt. If max_bytes is -1, a full-file + * clone will be attempted. Otherwise Linux copy_file_range(), sendfile() + * syscall will be attempted. If none of those work, this function will do a + * plain read()/write() loop. + * + * The file descriptor @fdf must refer to a regular file. + * + * If provided, @max_bytes specifies the maximum number of bytes to read from @fdf. + * On error, this function returns `-1` and @errno will be set. + */ +int +glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes) +{ + /* Last updates from systemd as of commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca */ + static int have_cfr = -1; /* -1 means unknown */ + bool try_cfr = have_cfr != 0; + static int have_sendfile = -1; /* -1 means unknown */ + bool try_sendfile = have_sendfile != 0; + + g_return_val_if_fail (fdf >= 0, -1); + g_return_val_if_fail (fdt >= 0, -1); + g_return_val_if_fail (max_bytes >= -1, -1); + + /* If we've requested to copy the whole range, try a full-file clone first. + */ + if (max_bytes == (off_t) -1) + { + if (ioctl (fdt, FICLONE, fdf) == 0) + return 0; + /* Fall through */ + struct stat stbuf; + + /* Gather the size so we can provide the whole thing at once to + * copy_file_range() or sendfile(). + */ + if (fstat (fdf, &stbuf) < 0) + return -1; + max_bytes = stbuf.st_size; + } + + while (TRUE) + { + ssize_t n; + + /* First, try copy_file_range(). Note this is an inlined version of + * try_copy_file_range() from systemd upstream, which works better since + * we use POSIX errno style. + */ + if (try_cfr) + { + n = copy_file_range (fdf, NULL, fdt, NULL, max_bytes, 0u); + if (n < 0) + { + if (errno == ENOSYS) + { + /* No cfr in kernel, mark as permanently unavailable + * and fall through to sendfile(). + */ + have_cfr = 0; + try_cfr = false; + } + else if (G_IN_SET (errno, EXDEV, EOPNOTSUPP)) + /* We won't try cfr again for this run, but let's be + * conservative and not mark it as available/unavailable until + * we know for sure. + */ + try_cfr = false; + else + return -1; + } + else + { + /* cfr worked, mark it as available */ + if (have_cfr == -1) + have_cfr = 1; + + if (n == 0) /* EOF */ + break; + else + /* Success! */ + goto next; + } + } + + /* Next try sendfile(); this version is also changed from systemd upstream + * to match the same logic we have for copy_file_range(). + */ + if (try_sendfile) + { + n = sendfile (fdt, fdf, NULL, max_bytes); + if (n < 0) + { + if (G_IN_SET (errno, EINVAL, ENOSYS)) + { + /* No sendfile(), or it doesn't work on regular files. + * Mark it as permanently unavailable, and fall through + * to plain read()/write(). + */ + have_sendfile = 0; + try_sendfile = false; + } + else + return -1; + } + else + { + /* sendfile() worked, mark it as available */ + if (have_sendfile == -1) + have_sendfile = 1; + + if (n == 0) /* EOF */ + break; + else if (n > 0) + /* Succcess! */ + goto next; + } + } + + /* As a fallback just copy bits by hand */ + { size_t m = COPY_BUFFER_SIZE; + if (max_bytes != (off_t) -1) + { + if ((off_t) m > max_bytes) + m = (size_t) max_bytes; + } + char buf[m]; + + n = TEMP_FAILURE_RETRY (read (fdf, buf, m)); + if (n < 0) + return -1; + if (n == 0) /* EOF */ + break; + + if (glnx_loop_write (fdt, buf, (size_t) n) < 0) + return -1; + } + + next: + if (max_bytes != (off_t) -1) + { + g_assert_cmpint (max_bytes, >=, n); + max_bytes -= n; + if (max_bytes == 0) + break; + } + } + + return 0; +} + +/** + * glnx_file_copy_at: + * @src_dfd: Source directory fd + * @src_subpath: Subpath relative to @src_dfd + * @src_stbuf: (allow-none): Optional stat buffer for source; if a stat() has already been done + * @dest_dfd: Target directory fd + * @dest_subpath: Destination name + * @copyflags: Flags + * @cancellable: cancellable + * @error: Error + * + * Perform a full copy of the regular file or symbolic link from @src_subpath to + * @dest_subpath; if @src_subpath is anything other than a regular file or + * symbolic link, an error will be returned. + * + * If the source is a regular file and the destination exists as a symbolic + * link, the symbolic link will not be followed; rather the link itself will be + * replaced. Related to this: for regular files, when `GLNX_FILE_COPY_OVERWRITE` + * is specified, this function always uses `O_TMPFILE` (if available) and does a + * rename-into-place rather than `open(O_TRUNC)`. + */ +gboolean +glnx_file_copy_at (int src_dfd, + const char *src_subpath, + const struct stat *src_stbuf, + int dest_dfd, + const char *dest_subpath, + GLnxFileCopyFlags copyflags, + GCancellable *cancellable, + GError **error) +{ + /* Canonicalize dfds */ + src_dfd = glnx_dirfd_canonicalize (src_dfd); + dest_dfd = glnx_dirfd_canonicalize (dest_dfd); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + /* Automatically do stat() if no stat buffer was supplied */ + struct stat local_stbuf; + if (!src_stbuf) + { + if (!glnx_fstatat (src_dfd, src_subpath, &local_stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + src_stbuf = &local_stbuf; + } + + /* For symlinks, defer entirely to copy_symlink_at() */ + if (S_ISLNK (src_stbuf->st_mode)) + { + return copy_symlink_at (src_dfd, src_subpath, src_stbuf, + dest_dfd, dest_subpath, + copyflags, + cancellable, error); + } + else if (!S_ISREG (src_stbuf->st_mode)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Cannot copy non-regular/non-symlink file: %s", src_subpath); + return FALSE; + } + + /* Regular file path below here */ + + glnx_autofd int src_fd = -1; + if (!glnx_openat_rdonly (src_dfd, src_subpath, FALSE, &src_fd, error)) + return FALSE; + + /* Open a tmpfile for dest. Particularly for AT_FDCWD calls, we really want to + * open in the target directory, otherwise we may not be able to link. + */ + g_auto(GLnxTmpfile) tmp_dest = { 0, }; + { char *dnbuf = strdupa (dest_subpath); + const char *dn = dirname (dnbuf); + if (!glnx_open_tmpfile_linkable_at (dest_dfd, dn, O_WRONLY | O_CLOEXEC, + &tmp_dest, error)) + return FALSE; + } + + if (glnx_regfile_copy_bytes (src_fd, tmp_dest.fd, (off_t) -1) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); + + if (fchown (tmp_dest.fd, src_stbuf->st_uid, src_stbuf->st_gid) != 0) + return glnx_throw_errno_prefix (error, "fchown"); + + if (!(copyflags & GLNX_FILE_COPY_NOXATTRS)) + { + g_autoptr(GVariant) xattrs = NULL; + + if (!glnx_fd_get_all_xattrs (src_fd, &xattrs, + cancellable, error)) + return FALSE; + + if (!glnx_fd_set_all_xattrs (tmp_dest.fd, xattrs, + cancellable, error)) + return FALSE; + } + + /* Always chmod after setting xattrs, in case the file has mode 0400 or less, + * like /etc/shadow. Linux currently allows write() on non-writable open files + * but not fsetxattr(). + */ + if (fchmod (tmp_dest.fd, src_stbuf->st_mode & 07777) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + struct timespec ts[2]; + ts[0] = src_stbuf->st_atim; + ts[1] = src_stbuf->st_mtim; + (void) futimens (tmp_dest.fd, ts); + + if (copyflags & GLNX_FILE_COPY_DATASYNC) + { + if (fdatasync (tmp_dest.fd) < 0) + return glnx_throw_errno_prefix (error, "fdatasync"); + } + + const GLnxLinkTmpfileReplaceMode replacemode = + (copyflags & GLNX_FILE_COPY_OVERWRITE) ? + GLNX_LINK_TMPFILE_REPLACE : + GLNX_LINK_TMPFILE_NOREPLACE; + + if (!glnx_link_tmpfile_at (&tmp_dest, replacemode, dest_dfd, dest_subpath, error)) + return FALSE; + + return TRUE; +} + +/** + * glnx_file_replace_contents_at: + * @dfd: Directory fd + * @subpath: Subpath + * @buf: (array len=len) (element-type guint8): File contents + * @len: Length (if `-1`, assume @buf is `NUL` terminated) + * @flags: Flags + * @cancellable: Cancellable + * @error: Error + * + * Create a new file, atomically replacing the contents of @subpath + * (relative to @dfd) with @buf. By default, if the file already + * existed, fdatasync() will be used before rename() to ensure stable + * contents. This and other behavior can be controlled via @flags. + * + * Note that no metadata from the existing file is preserved, such as + * uid/gid or extended attributes. The default mode will be `0644`. + */ +gboolean +glnx_file_replace_contents_at (int dfd, + const char *subpath, + const guint8 *buf, + gsize len, + GLnxFileReplaceFlags flags, + GCancellable *cancellable, + GError **error) +{ + return glnx_file_replace_contents_with_perms_at (dfd, subpath, buf, len, + (mode_t) -1, (uid_t) -1, (gid_t) -1, + flags, cancellable, error); +} + +/** + * glnx_file_replace_contents_with_perms_at: + * @dfd: Directory fd + * @subpath: Subpath + * @buf: (array len=len) (element-type guint8): File contents + * @len: Length (if `-1`, assume @buf is `NUL` terminated) + * @mode: File mode; if `-1`, use `0644` + * @flags: Flags + * @cancellable: Cancellable + * @error: Error + * + * Like glnx_file_replace_contents_at(), but also supports + * setting mode, and uid/gid. + */ +gboolean +glnx_file_replace_contents_with_perms_at (int dfd, + const char *subpath, + const guint8 *buf, + gsize len, + mode_t mode, + uid_t uid, + gid_t gid, + GLnxFileReplaceFlags flags, + GCancellable *cancellable, + GError **error) +{ + char *dnbuf = strdupa (subpath); + const char *dn = dirname (dnbuf); + + dfd = glnx_dirfd_canonicalize (dfd); + + /* With O_TMPFILE we can't use umask, and we can't sanely query the + * umask...let's assume something relatively standard. + */ + if (mode == (mode_t) -1) + mode = 0644; + + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (dfd, dn, O_WRONLY | O_CLOEXEC, + &tmpf, error)) + return FALSE; + + if (len == -1) + len = strlen ((char*)buf); + + if (!glnx_try_fallocate (tmpf.fd, 0, len, error)) + return FALSE; + + if (glnx_loop_write (tmpf.fd, buf, len) < 0) + return glnx_throw_errno_prefix (error, "write"); + + if (!(flags & GLNX_FILE_REPLACE_NODATASYNC)) + { + struct stat stbuf; + gboolean do_sync; + + if (!glnx_fstatat_allow_noent (dfd, subpath, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == ENOENT) + do_sync = (flags & GLNX_FILE_REPLACE_DATASYNC_NEW) > 0; + else + do_sync = TRUE; + + if (do_sync) + { + if (fdatasync (tmpf.fd) != 0) + return glnx_throw_errno_prefix (error, "fdatasync"); + } + } + + if (uid != (uid_t) -1) + { + if (fchown (tmpf.fd, uid, gid) != 0) + return glnx_throw_errno_prefix (error, "fchown"); + } + + if (fchmod (tmpf.fd, mode) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE, + dfd, subpath, error)) + return FALSE; + + return TRUE; +} diff --git a/libglnx/glnx-fdio.h b/libglnx/glnx-fdio.h new file mode 100644 index 0000000..f95e473 --- /dev/null +++ b/libglnx/glnx-fdio.h @@ -0,0 +1,380 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +// For dirname(), and previously basename() +#include + +#include +#include + +G_BEGIN_DECLS + +/* Irritatingly, g_basename() which is what we want + * is deprecated. + */ +static inline +const char *glnx_basename (const char *path) +{ + gchar *base = strrchr (path, G_DIR_SEPARATOR); + + if (base) + return base + 1; + + return path; +} + +/* Utilities for standard FILE* */ +static inline void +glnx_stdio_file_cleanup (void *filep) +{ + FILE *f = filep; + if (f) + fclose (f); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FILE, glnx_stdio_file_cleanup) + +/** + * glnx_stdio_file_flush: + * Call fflush() and check ferror(). + */ +gboolean +glnx_stdio_file_flush (FILE *f, GError **error); + +typedef struct { + gboolean initialized; + gboolean anonymous; + int src_dfd; + int fd; + char *path; +} GLnxTmpfile; +void glnx_tmpfile_clear (GLnxTmpfile *tmpf); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxTmpfile, glnx_tmpfile_clear) + +gboolean +glnx_open_anonymous_tmpfile (int flags, + GLnxTmpfile *out_tmpf, + GError **error); + +gboolean +glnx_open_anonymous_tmpfile_full (int flags, + const char *dir, + GLnxTmpfile *out_tmpf, + GError **error); + + +gboolean +glnx_open_tmpfile_linkable_at (int dfd, + const char *subpath, + int flags, + GLnxTmpfile *out_tmpf, + GError **error); + +typedef enum { + GLNX_LINK_TMPFILE_REPLACE, + GLNX_LINK_TMPFILE_NOREPLACE, + GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST +} GLnxLinkTmpfileReplaceMode; + +gboolean +glnx_link_tmpfile_at (GLnxTmpfile *tmpf, + GLnxLinkTmpfileReplaceMode flags, + int target_dfd, + const char *target, + GError **error); + +gboolean +glnx_tmpfile_reopen_rdonly (GLnxTmpfile *tmpf, + GError **error); + +gboolean +glnx_openat_rdonly (int dfd, + const char *path, + gboolean follow, + int *out_fd, + GError **error); + +GBytes * +glnx_fd_readall_bytes (int fd, + GCancellable *cancellable, + GError **error); + +char * +glnx_fd_readall_utf8 (int fd, + gsize *out_len, + GCancellable *cancellable, + GError **error); + +char * +glnx_file_get_contents_utf8_at (int dfd, + const char *subpath, + gsize *out_len, + GCancellable *cancellable, + GError **error); + +/** + * GLnxFileReplaceFlags: + * @GLNX_FILE_REPLACE_DATASYNC_NEW: Call fdatasync() even if the file did not exist + * @GLNX_FILE_REPLACE_NODATASYNC: Never call fdatasync() + * + * Flags controlling file replacement. + */ +typedef enum { + GLNX_FILE_REPLACE_DATASYNC_NEW = (1 << 0), + GLNX_FILE_REPLACE_NODATASYNC = (1 << 1), +} GLnxFileReplaceFlags; + +gboolean +glnx_file_replace_contents_at (int dfd, + const char *subpath, + const guint8 *buf, + gsize len, + GLnxFileReplaceFlags flags, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_file_replace_contents_with_perms_at (int dfd, + const char *subpath, + const guint8 *buf, + gsize len, + mode_t mode, + uid_t uid, + gid_t gid, + GLnxFileReplaceFlags flags, + GCancellable *cancellable, + GError **error); + +char * +glnx_readlinkat_malloc (int dfd, + const char *subpath, + GCancellable *cancellable, + GError **error); + +int +glnx_loop_write (int fd, const void *buf, size_t nbytes); + +int +glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes); + +typedef enum { + GLNX_FILE_COPY_OVERWRITE = (1 << 0), + GLNX_FILE_COPY_NOXATTRS = (1 << 1), + GLNX_FILE_COPY_DATASYNC = (1 << 2) +} GLnxFileCopyFlags; + +gboolean +glnx_file_copy_at (int src_dfd, + const char *src_subpath, + const struct stat *src_stbuf, + int dest_dfd, + const char *dest_subpath, + GLnxFileCopyFlags copyflags, + GCancellable *cancellable, + GError **error); + +int glnx_renameat2_noreplace (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath); +int glnx_renameat2_exchange (int olddirfd, const char *oldpath, + int newdirfd, const char *newpath); + +/** + * glnx_try_fallocate: + * @fd: File descriptor + * @size: Size + * @error: Error + * + * Wrapper for Linux fallocate(). Explicitly ignores a @size of zero. + * Also, will silently do nothing if the underlying filesystem doesn't + * support it. Use this instead of posix_fallocate(), since the glibc fallback + * is bad: https://sourceware.org/bugzilla/show_bug.cgi?id=18515 + */ +static inline gboolean +glnx_try_fallocate (int fd, + off_t offset, + off_t size, + GError **error) +{ + /* This is just nicer than throwing an error */ + if (size == 0) + return TRUE; + + if (fallocate (fd, 0, offset, size) < 0) + { + if (G_IN_SET(errno, ENOSYS, EOPNOTSUPP)) + ; /* Ignore */ + else + return glnx_throw_errno_prefix (error, "fallocate"); + } + + return TRUE; +} + +/** + * glnx_fstat: + * @fd: FD to stat + * @buf: (out caller-allocates): Return location for stat details + * @error: Return location for a #GError, or %NULL + * + * Wrapper around fstat() which adds #GError support and ensures that it retries + * on %EINTR. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +static inline gboolean +glnx_fstat (int fd, + struct stat *buf, + GError **error) +{ + if (TEMP_FAILURE_RETRY (fstat (fd, buf)) != 0) + return glnx_throw_errno_prefix (error, "fstat"); + return TRUE; +} + +/** + * glnx_fchmod: + * @fd: FD + * @mode: Mode + * @error: Return location for a #GError, or %NULL + * + * Wrapper around fchmod() which adds #GError support and ensures that it + * retries on %EINTR. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +static inline gboolean +glnx_fchmod (int fd, + mode_t mode, + GError **error) +{ + if (TEMP_FAILURE_RETRY (fchmod (fd, mode)) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + return TRUE; +} + +/** + * glnx_fstatat: + * @dfd: Directory FD to stat beneath + * @path: Path to stat beneath @dfd + * @buf: (out caller-allocates): Return location for stat details + * @flags: Flags to pass to fstatat() + * @error: Return location for a #GError, or %NULL + * + * Wrapper around fstatat() which adds #GError support and ensures that it + * retries on %EINTR. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +static inline gboolean +glnx_fstatat (int dfd, + const gchar *path, + struct stat *buf, + int flags, + GError **error) +{ + if (TEMP_FAILURE_RETRY (fstatat (dfd, path, buf, flags)) != 0) + return glnx_throw_errno_prefix (error, "fstatat(%s)", path); + return TRUE; +} + +/** + * glnx_fstatat_allow_noent: + * @dfd: Directory FD to stat beneath + * @path: Path to stat beneath @dfd + * @buf: (out caller-allocates) (allow-none): Return location for stat details + * @flags: Flags to pass to fstatat() + * @error: Return location for a #GError, or %NULL + * + * Like glnx_fstatat(), but handles `ENOENT` in a non-error way. Instead, + * on success `errno` will be zero, otherwise it will be preserved. Hence + * you can test `if (errno == 0)` to conditionalize on the file existing, + * or `if (errno == ENOENT)` for non-existence. + * + * Returns: %TRUE on success, %FALSE otherwise (errno is preserved) + * Since: UNRELEASED + */ +static inline gboolean +glnx_fstatat_allow_noent (int dfd, + const char *path, + struct stat *out_buf, + int flags, + GError **error) +{ + G_GNUC_UNUSED struct stat unused_stbuf; + if (TEMP_FAILURE_RETRY (fstatat (dfd, path, out_buf ? out_buf : &unused_stbuf, flags)) != 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "fstatat(%s)", path); + /* Note we preserve errno as ENOENT */ + } + else + errno = 0; + return TRUE; +} + +/** + * glnx_renameat: + * + * Wrapper around renameat() which adds #GError support and ensures that it + * retries on %EINTR. + */ +static inline gboolean +glnx_renameat (int src_dfd, + const gchar *src_path, + int dest_dfd, + const gchar *dest_path, + GError **error) +{ + if (TEMP_FAILURE_RETRY (renameat (src_dfd, src_path, dest_dfd, dest_path)) != 0) + return glnx_throw_errno_prefix (error, "renameat(%s, %s)", src_path, dest_path); + return TRUE; +} + +/** + * glnx_unlinkat: + * + * Wrapper around unlinkat() which adds #GError support and ensures that it + * retries on %EINTR. + */ +static inline gboolean +glnx_unlinkat (int dfd, + const gchar *path, + int flags, + GError **error) +{ + if (TEMP_FAILURE_RETRY (unlinkat (dfd, path, flags)) != 0) + return glnx_throw_errno_prefix (error, "unlinkat(%s)", path); + return TRUE; +} + +G_END_DECLS diff --git a/libglnx/glnx-local-alloc.c b/libglnx/glnx-local-alloc.c new file mode 100644 index 0000000..692f0de --- /dev/null +++ b/libglnx/glnx-local-alloc.c @@ -0,0 +1,72 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2012,2015 Colin Walters + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "glnx-local-alloc.h" + +/** + * SECTION:glnxlocalalloc + * @title: GLnx local allocation + * @short_description: Release local variables automatically when they go out of scope + * + * These macros leverage the GCC extension __attribute__ ((cleanup)) + * to allow calling a cleanup function such as g_free() when a + * variable goes out of scope. See + * for more information on the attribute. + * + * The provided macros make it easy to use the cleanup attribute for + * types that come with GLib. The primary two are #glnx_free and + * #glnx_unref_object, which correspond to g_free() and + * g_object_unref(), respectively. + * + * The rationale behind this is that particularly when handling error + * paths, it can be very tricky to ensure the right variables are + * freed. With this, one simply applies glnx_unref_object to a + * locally-allocated #GFile for example, and it will be automatically + * unreferenced when it goes out of scope. + * + * Note - you should only use these macros for stack + * allocated variables. They don't provide garbage + * collection or let you avoid freeing things. They're simply a + * compiler assisted deterministic mechanism for calling a cleanup + * function when a stack frame ends. + * + * Calling g_free automatically + * + * + * GFile * + * create_file (GError **error) + * { + * glnx_free char *random_id = NULL; + * + * if (!prepare_file (error)) + * return NULL; + * + * random_id = alloc_random_id (); + * + * return create_file_real (error); + * // Note that random_id is freed here automatically + * } + * + * + * + */ diff --git a/libglnx/glnx-local-alloc.h b/libglnx/glnx-local-alloc.h new file mode 100644 index 0000000..3be1fa4 --- /dev/null +++ b/libglnx/glnx-local-alloc.h @@ -0,0 +1,91 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2012,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +/** + * glnx_unref_object: + * + * Call g_object_unref() on a variable location when it goes out of + * scope. Note that unlike g_object_unref(), the variable may be + * %NULL. + */ +#define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref))) +static inline void +glnx_local_obj_unref (void *v) +{ + GObject *o = *(GObject **)v; + if (o) + g_object_unref (o); +} +#define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref))) + +static inline int +glnx_steal_fd (int *fdp) +{ + int fd = *fdp; + *fdp = -1; + return fd; +} + +/** + * glnx_close_fd: + * @fdp: Pointer to fd + * + * Effectively `close (glnx_steal_fd (&fd))`. Also + * asserts that `close()` did not raise `EBADF` - encountering + * that error is usually a critical bug in the program. + */ +static inline void +glnx_close_fd (int *fdp) +{ + int errsv; + + g_assert (fdp); + + int fd = glnx_steal_fd (fdp); + if (fd >= 0) + { + errsv = errno; + if (close (fd) < 0) + g_assert (errno != EBADF); + errno = errsv; + } +} + +/** + * glnx_fd_close: + * + * Deprecated in favor of `glnx_autofd`. + */ +#define glnx_fd_close __attribute__((cleanup(glnx_close_fd))) +/** + * glnx_autofd: + * + * Call close() on a variable location when it goes out of scope. + */ +#define glnx_autofd __attribute__((cleanup(glnx_close_fd))) + +G_END_DECLS diff --git a/libglnx/glnx-lockfile.c b/libglnx/glnx-lockfile.c new file mode 100644 index 0000000..f1d52de --- /dev/null +++ b/libglnx/glnx-lockfile.c @@ -0,0 +1,179 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + Now copied into libglnx: + - Use GError + + Copyright 2010 Lennart Poettering + Copyright 2015 Colin Walters + + systemd 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. + + systemd 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 systemd; If not, see . +***/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "glnx-lockfile.h" +#include "glnx-errors.h" +#include "glnx-fdio.h" +#include "glnx-backport-autocleanups.h" +#include "glnx-local-alloc.h" + +#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) + +/** + * glnx_make_lock_file: + * @dfd: Directory file descriptor (if not `AT_FDCWD`, must have lifetime `>=` @out_lock) + * @p: Path + * @operation: one of `LOCK_SH`, `LOCK_EX`, `LOCK_UN`, as passed to flock() + * @out_lock: (out) (caller allocates): Return location for lock + * @error: Error + * + * Block until a lock file named @p (relative to @dfd) can be created, + * using the flags in @operation, returning the lock data in the + * caller-allocated location @out_lock. + * + * This API wraps new-style process locking if available, otherwise + * falls back to BSD locks. + */ +gboolean +glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_lock, GError **error) { + glnx_autofd int fd = -1; + g_autofree char *t = NULL; + int r; + + /* + * We use UNPOSIX locks if they are available. They have nice + * semantics, and are mostly compatible with NFS. However, + * they are only available on new kernels. When we detect we + * are running on an older kernel, then we fall back to good + * old BSD locks. They also have nice semantics, but are + * slightly problematic on NFS, where they are upgraded to + * POSIX locks, even though locally they are orthogonal to + * POSIX locks. + */ + + t = g_strdup(p); + + for (;;) { +#ifdef F_OFD_SETLK + struct flock fl = { + .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK, + .l_whence = SEEK_SET, + }; +#endif + struct stat st; + + fd = openat(dfd, p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600); + if (fd < 0) + return glnx_throw_errno(error); + + /* Unfortunately, new locks are not in RHEL 7.1 glibc */ +#ifdef F_OFD_SETLK + r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl); +#else + r = -1; + errno = EINVAL; +#endif + if (r < 0) { + + /* If the kernel is too old, use good old BSD locks */ + if (errno == EINVAL) + r = flock(fd, operation); + + if (r < 0) + return glnx_throw_errno_prefix (error, "flock"); + } + + /* If we acquired the lock, let's check if the file + * still exists in the file system. If not, then the + * previous exclusive owner removed it and then closed + * it. In such a case our acquired lock is worthless, + * hence try again. */ + + if (!glnx_fstat (fd, &st, error)) + return FALSE; + if (st.st_nlink > 0) + break; + + glnx_close_fd (&fd); + } + + /* Note that if this is not AT_FDCWD, the caller takes responsibility + * for the fd's lifetime being >= that of the lock. + */ + out_lock->initialized = TRUE; + out_lock->dfd = dfd; + out_lock->path = g_steal_pointer (&t); + out_lock->fd = glnx_steal_fd (&fd); + out_lock->operation = operation; + return TRUE; +} + +void glnx_release_lock_file(GLnxLockFile *f) { + int r; + + if (!(f && f->initialized)) + return; + + if (f->path) { + + /* If we are the exclusive owner we can safely delete + * the lock file itself. If we are not the exclusive + * owner, we can try becoming it. */ + + if (f->fd >= 0 && + (f->operation & ~LOCK_NB) == LOCK_SH) { +#ifdef F_OFD_SETLK + static const struct flock fl = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + }; + + r = fcntl(f->fd, F_OFD_SETLK, &fl); +#else + r = -1; + errno = EINVAL; +#endif + if (r < 0 && errno == EINVAL) + r = flock(f->fd, LOCK_EX|LOCK_NB); + + if (r >= 0) + f->operation = LOCK_EX|LOCK_NB; + } + + if ((f->operation & ~LOCK_NB) == LOCK_EX) { + (void) unlinkat(f->dfd, f->path, 0); + } + + g_free(f->path); + f->path = NULL; + } + + glnx_close_fd (&f->fd); + f->operation = 0; + f->initialized = FALSE; +} diff --git a/libglnx/glnx-lockfile.h b/libglnx/glnx-lockfile.h new file mode 100644 index 0000000..b346508 --- /dev/null +++ b/libglnx/glnx-lockfile.h @@ -0,0 +1,40 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + Copyright 2015 Colin Walters + + systemd 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. + + systemd 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 systemd; If not, see . +***/ + +#include "config.h" + +#include "glnx-backport-autoptr.h" + +typedef struct GLnxLockFile { + gboolean initialized; + int dfd; + char *path; + int fd; + int operation; +} GLnxLockFile; + +gboolean glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *ret, GError **error); +void glnx_release_lock_file(GLnxLockFile *f); + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GLnxLockFile, glnx_release_lock_file) diff --git a/libglnx/glnx-macros.h b/libglnx/glnx-macros.h new file mode 100644 index 0000000..700fc75 --- /dev/null +++ b/libglnx/glnx-macros.h @@ -0,0 +1,199 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Colin Walters + * With original source from systemd: + * Copyright 2010 Lennart Poettering + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +/* All of these are for C only. */ +#ifndef __GI_SCANNER__ + +/* fixes builds against musl, taken from glibc unistd.h */ +#ifndef TEMP_FAILURE_RETRY +#define TEMP_FAILURE_RETRY(expression) \ + (__extension__ \ + ({ long int __result; \ + do __result = (long int) (expression); \ + while (__result == -1L && errno == EINTR); \ + __result; })) +#endif + +/* Taken from https://github.com/systemd/systemd/src/basic/string-util.h + * at revision v228-666-gcf6c8c4 + */ +#define glnx_strjoina(a, ...) \ + ({ \ + const char *_appendees_[] = { a, __VA_ARGS__ }; \ + char *_d_, *_p_; \ + size_t _len_ = 0; \ + unsigned _i_; \ + for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \ + _len_ += strlen(_appendees_[_i_]); \ + _p_ = _d_ = alloca(_len_ + 1); \ + for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \ + _p_ = stpcpy(_p_, _appendees_[_i_]); \ + *_p_ = 0; \ + _d_; \ + }) + +#ifndef G_IN_SET + +/* Infrastructure for `G_IN_SET`; this code is copied from + * systemd's macro.h - please treat that version as canonical + * and submit patches first to systemd. + */ +#define _G_INSET_CASE_F(X) case X: +#define _G_INSET_CASE_F_1(CASE, X) _G_INSET_CASE_F(X) +#define _G_INSET_CASE_F_2(CASE, X, ...) CASE(X) _G_INSET_CASE_F_1(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_3(CASE, X, ...) CASE(X) _G_INSET_CASE_F_2(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_4(CASE, X, ...) CASE(X) _G_INSET_CASE_F_3(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_5(CASE, X, ...) CASE(X) _G_INSET_CASE_F_4(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_6(CASE, X, ...) CASE(X) _G_INSET_CASE_F_5(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_7(CASE, X, ...) CASE(X) _G_INSET_CASE_F_6(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_8(CASE, X, ...) CASE(X) _G_INSET_CASE_F_7(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_9(CASE, X, ...) CASE(X) _G_INSET_CASE_F_8(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_10(CASE, X, ...) CASE(X) _G_INSET_CASE_F_9(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_11(CASE, X, ...) CASE(X) _G_INSET_CASE_F_10(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_12(CASE, X, ...) CASE(X) _G_INSET_CASE_F_11(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_13(CASE, X, ...) CASE(X) _G_INSET_CASE_F_12(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_14(CASE, X, ...) CASE(X) _G_INSET_CASE_F_13(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_15(CASE, X, ...) CASE(X) _G_INSET_CASE_F_14(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_16(CASE, X, ...) CASE(X) _G_INSET_CASE_F_15(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_17(CASE, X, ...) CASE(X) _G_INSET_CASE_F_16(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_18(CASE, X, ...) CASE(X) _G_INSET_CASE_F_17(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_19(CASE, X, ...) CASE(X) _G_INSET_CASE_F_18(CASE, __VA_ARGS__) +#define _G_INSET_CASE_F_20(CASE, X, ...) CASE(X) _G_INSET_CASE_F_19(CASE, __VA_ARGS__) + +#define _G_INSET_GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME +#define _G_INSET_FOR_EACH_MAKE_CASE(...) \ + _G_INSET_GET_CASE_F(__VA_ARGS__,_G_INSET_CASE_F_20,_G_INSET_CASE_F_19,_G_INSET_CASE_F_18,_G_INSET_CASE_F_17,_G_INSET_CASE_F_16,_G_INSET_CASE_F_15,_G_INSET_CASE_F_14,_G_INSET_CASE_F_13,_G_INSET_CASE_F_12,_G_INSET_CASE_F_11, \ + _G_INSET_CASE_F_10,_G_INSET_CASE_F_9,_G_INSET_CASE_F_8,_G_INSET_CASE_F_7,_G_INSET_CASE_F_6,_G_INSET_CASE_F_5,_G_INSET_CASE_F_4,_G_INSET_CASE_F_3,_G_INSET_CASE_F_2,_G_INSET_CASE_F_1) \ + (_G_INSET_CASE_F,__VA_ARGS__) + +/* Note: claiming the name here even though it isn't upstream yet + * https://bugzilla.gnome.org/show_bug.cgi?id=783751 + */ +/** + * G_IN_SET: + * @x: Integer (or smaller) sized value + * @...: Elements to compare + * + * It's quite common to test whether or not `char` values or Unix @errno (among) others + * are members of a small set. Normally one has to choose to either use `if (x == val || x == otherval ...)` + * or a `switch` statement. This macro is useful to reduce duplication in the first case, + * where one can write simply `if (G_IN_SET (x, val, otherval))`, and avoid the verbosity + * that the `switch` statement requires. + */ +#define G_IN_SET(x, ...) \ + ({ \ + gboolean _g_inset_found = FALSE; \ + /* If the build breaks in the line below, you need to extend the case macros */ \ + static G_GNUC_UNUSED char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){__VA_ARGS__})/sizeof(int)]; \ + switch(x) { \ + _G_INSET_FOR_EACH_MAKE_CASE(__VA_ARGS__) \ + _g_inset_found = TRUE; \ + break; \ + default: \ + break; \ + } \ + _g_inset_found; \ + }) + +#endif /* ifndef G_IN_SET */ + +#define _GLNX_CONCAT(a, b) a##b +#define _GLNX_CONCAT_INDIRECT(a, b) _GLNX_CONCAT(a, b) +#define _GLNX_MAKE_ANONYMOUS(a) _GLNX_CONCAT_INDIRECT(a, __COUNTER__) + +#define _GLNX_HASH_TABLE_FOREACH_IMPL_KV(guard, ht, it, kt, k, vt, v) \ + gboolean guard = TRUE; \ + G_STATIC_ASSERT (sizeof (kt) == sizeof (void*)); \ + G_STATIC_ASSERT (sizeof (vt) == sizeof (void*)); \ + for (GHashTableIter it; \ + guard && ({ g_hash_table_iter_init (&it, ht), TRUE; }); \ + guard = FALSE) \ + for (kt k; guard; guard = FALSE) \ + for (vt v; g_hash_table_iter_next (&it, (gpointer)&k, (gpointer)&v);) + + +/* Cleaner method to iterate over a GHashTable. I.e. rather than + * + * gpointer k, v; + * GHashTableIter it; + * g_hash_table_iter_init (&it, table); + * while (g_hash_table_iter_next (&it, &k, &v)) + * { + * const char *str = k; + * GPtrArray *arr = v; + * ... + * } + * + * you can simply do + * + * GLNX_HASH_TABLE_FOREACH_IT (table, it, const char*, str, GPtrArray*, arr) + * { + * ... + * } + * + * All variables are scoped within the loop. You may use the `it` variable as + * usual, e.g. to remove an element using g_hash_table_iter_remove(&it). There + * are shorter variants for the more common cases where you do not need access + * to the iterator or to keys/values: + * + * GLNX_HASH_TABLE_FOREACH (table, const char*, str) { ... } + * GLNX_HASH_TABLE_FOREACH_V (table, MyData*, data) { ... } + * GLNX_HASH_TABLE_FOREACH_KV (table, const char*, str, MyData*, data) { ... } + * + */ +#define GLNX_HASH_TABLE_FOREACH_IT(ht, it, kt, k, vt, v) \ + _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, it, kt, k, vt, v) + +/* Variant of GLNX_HASH_TABLE_FOREACH without having to specify an iterator. An + * anonymous iterator will be created. */ +#define GLNX_HASH_TABLE_FOREACH_KV(ht, kt, k, vt, v) \ + _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), kt, k, vt, v) + +/* Variant of GLNX_HASH_TABLE_FOREACH_KV which omits unpacking keys. */ +#define GLNX_HASH_TABLE_FOREACH_V(ht, vt, v) \ + _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), \ + gpointer, _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_v_), \ + vt, v) + +/* Variant of GLNX_HASH_TABLE_FOREACH_KV which omits unpacking vals. */ +#define GLNX_HASH_TABLE_FOREACH(ht, kt, k) \ + _GLNX_HASH_TABLE_FOREACH_IMPL_KV( \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_guard_), ht, \ + _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_it_), kt, k, \ + gpointer, _GLNX_MAKE_ANONYMOUS(_glnx_ht_iter_v_)) + +#endif /* GI_SCANNER */ + +G_END_DECLS diff --git a/libglnx/glnx-missing-syscall.h b/libglnx/glnx-missing-syscall.h new file mode 100644 index 0000000..4876ca3 --- /dev/null +++ b/libglnx/glnx-missing-syscall.h @@ -0,0 +1,156 @@ +/*** + This file was originally part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd 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. + + systemd 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 systemd; If not, see . +***/ + +/* Missing glibc definitions to access certain kernel APIs. + This file is last updated from systemd git: + + commit 71e5200f94b22589922704aa4abdf95d4fe2e528 + Author: Daniel Mack + AuthorDate: Tue Oct 18 17:57:10 2016 +0200 + Commit: Lennart Poettering + CommitDate: Fri Sep 22 15:24:54 2017 +0200 + + Add abstraction model for BPF programs +*/ + +#include "config.h" + +#if !HAVE_DECL_RENAMEAT2 +# ifndef __NR_renameat2 +# if defined __x86_64__ +# define __NR_renameat2 316 +# elif defined __arm__ +# define __NR_renameat2 382 +# elif defined __aarch64__ +# define __NR_renameat2 276 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_renameat2 4351 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_renameat2 6315 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_renameat2 5311 +# endif +# elif defined __i386__ +# define __NR_renameat2 353 +# elif defined __powerpc64__ +# define __NR_renameat2 357 +# elif defined __s390__ || defined __s390x__ +# define __NR_renameat2 347 +# elif defined __arc__ +# define __NR_renameat2 276 +# else +# warning "__NR_renameat2 unknown for your architecture" +# endif +# endif + +static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { +# ifdef __NR_renameat2 + return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +#if !HAVE_DECL_MEMFD_CREATE +# ifndef __NR_memfd_create +# if defined __x86_64__ +# define __NR_memfd_create 319 +# elif defined __arm__ +# define __NR_memfd_create 385 +# elif defined __aarch64__ +# define __NR_memfd_create 279 +# elif defined __s390__ +# define __NR_memfd_create 350 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_memfd_create 4354 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_memfd_create 6318 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_memfd_create 5314 +# endif +# elif defined __i386__ +# define __NR_memfd_create 356 +# elif defined __arc__ +# define __NR_memfd_create 279 +# else +# warning "__NR_memfd_create unknown for your architecture" +# endif +# endif + +static inline int memfd_create(const char *name, unsigned int flags) { +# ifdef __NR_memfd_create + return syscall(__NR_memfd_create, name, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* Copied from systemd git: + commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca + Author: Yu Watanabe + AuthorDate: Thu Jul 27 20:22:54 2017 +0900 + Commit: Zbigniew Jędrzejewski-Szmek + CommitDate: Thu Jul 27 07:22:54 2017 -0400 +*/ +#if !HAVE_DECL_COPY_FILE_RANGE +# ifndef __NR_copy_file_range +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined __s390__ +# define __NR_copy_file_range 375 +# elif defined __arm__ +# define __NR_copy_file_range 391 +# elif defined __aarch64__ +# define __NR_copy_file_range 285 +# elif defined __powerpc__ +# define __NR_copy_file_range 379 +# elif defined __arc__ +# define __NR_copy_file_range 285 +# else +# warning "__NR_copy_file_range not defined for your architecture" +# endif +# endif + +static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { +# ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define copy_file_range missing_copy_file_range +#endif diff --git a/libglnx/glnx-missing.h b/libglnx/glnx-missing.h new file mode 100644 index 0000000..9d35c40 --- /dev/null +++ b/libglnx/glnx-missing.h @@ -0,0 +1,94 @@ +#pragma once + +/*** + This file was originally part of systemd. + + Copyright 2010 Lennart Poettering + + systemd 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. + + systemd 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 systemd; If not, see . +***/ + +/* Missing glibc definitions to access certain kernel APIs. + This file is last updated from systemd git: + + commit 71e5200f94b22589922704aa4abdf95d4fe2e528 + Author: Daniel Mack + AuthorDate: Tue Oct 18 17:57:10 2016 +0200 + Commit: Lennart Poettering + CommitDate: Fri Sep 22 15:24:54 2017 +0200 + + Add abstraction model for BPF programs +*/ + +#include +#include +#include +#include +#include +#include + +/* The precise definition of __O_TMPFILE is arch specific; use the + * values defined by the kernel (note: some are hexa, some are octal, + * duplicated as-is from the kernel definitions): + * - alpha, parisc, sparc: each has a specific value; + * - others: they use the "generic" value. + */ + +#ifndef __O_TMPFILE +#if defined(__alpha__) +#define __O_TMPFILE 0100000000 +#elif defined(__parisc__) || defined(__hppa__) +#define __O_TMPFILE 0400000000 +#elif defined(__sparc__) || defined(__sparc64__) +#define __O_TMPFILE 0x2000000 +#else +#define __O_TMPFILE 020000000 +#endif +#endif + +/* a horrid kludge trying to make sure that this will fail on old kernels */ +#ifndef O_TMPFILE +#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) +#endif + +#ifndef RENAME_NOREPLACE +#define RENAME_NOREPLACE (1 << 0) +#endif +#ifndef RENAME_EXCHANGE +#define RENAME_EXCHANGE (1 << 1) +#endif + +#ifndef F_LINUX_SPECIFIC_BASE +#define F_LINUX_SPECIFIC_BASE 1024 +#endif + +#ifndef F_ADD_SEALS +#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) +#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) + +#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ +#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ +#define F_SEAL_GROW 0x0004 /* prevent file from growing */ +#define F_SEAL_WRITE 0x0008 /* prevent writes */ +#endif + +#ifndef MFD_ALLOW_SEALING +#define MFD_ALLOW_SEALING 0x0002U +#endif + +#ifndef MFD_CLOEXEC +#define MFD_CLOEXEC 0x0001U +#endif + +#include "glnx-missing-syscall.h" diff --git a/libglnx/glnx-shutil.c b/libglnx/glnx-shutil.c new file mode 100644 index 0000000..78042fe --- /dev/null +++ b/libglnx/glnx-shutil.c @@ -0,0 +1,268 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include +#include +#include + +static gboolean +unlinkat_allow_noent (int dfd, + const char *path, + int flags, + GError **error) +{ + if (unlinkat (dfd, path, flags) == -1) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "unlinkat(%s)", path); + } + return TRUE; +} + +static gboolean +glnx_shutil_rm_rf_children (GLnxDirFdIterator *dfd_iter, + GCancellable *cancellable, + GError **error) +{ + struct dirent *dent; + + while (TRUE) + { + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (dent->d_type == DT_DIR) + { + g_auto(GLnxDirFdIterator) child_dfd_iter = { 0, }; + + if (!glnx_dirfd_iterator_init_at (dfd_iter->fd, dent->d_name, FALSE, + &child_dfd_iter, error)) + return FALSE; + + if (!glnx_shutil_rm_rf_children (&child_dfd_iter, cancellable, error)) + return FALSE; + + if (!glnx_unlinkat (dfd_iter->fd, dent->d_name, AT_REMOVEDIR, error)) + return FALSE; + } + else + { + if (!unlinkat_allow_noent (dfd_iter->fd, dent->d_name, 0, error)) + return FALSE; + } + } + + return TRUE; +} + +/** + * glnx_shutil_rm_rf_at: + * @dfd: A directory file descriptor, or `AT_FDCWD` or `-1` for current + * @path: Path + * @cancellable: Cancellable + * @error: Error + * + * Recursively delete the filename referenced by the combination of + * the directory fd @dfd and @path; it may be a file or directory. No + * error is thrown if @path does not exist. + */ +gboolean +glnx_shutil_rm_rf_at (int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + dfd = glnx_dirfd_canonicalize (dfd); + + /* With O_NOFOLLOW first */ + glnx_autofd int target_dfd = + openat (dfd, path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); + + if (target_dfd == -1) + { + int errsv = errno; + if (errsv == ENOENT) + { + ; + } + else if (errsv == ENOTDIR || errsv == ELOOP) + { + if (!glnx_unlinkat (dfd, path, 0, error)) + return FALSE; + } + else + return glnx_throw_errno_prefix (error, "open(%s)", path); + } + else + { + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_take_fd (&target_dfd, &dfd_iter, error)) + return FALSE; + + if (!glnx_shutil_rm_rf_children (&dfd_iter, cancellable, error)) + return glnx_prefix_error (error, "Removing %s", path); + + if (!unlinkat_allow_noent (dfd, path, AT_REMOVEDIR, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +mkdir_p_at_internal (int dfd, + char *path, + int mode, + GCancellable *cancellable, + GError **error) +{ + gboolean did_recurse = FALSE; + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + again: + if (mkdirat (dfd, path, mode) == -1) + { + if (errno == ENOENT) + { + char *lastslash; + + g_assert (!did_recurse); + + lastslash = strrchr (path, '/'); + if (lastslash == NULL) + { + /* This can happen if @dfd was deleted between being opened and + * passed to mkdir_p_at_internal(). */ + return glnx_throw_errno_prefix (error, "mkdir(%s)", path); + } + + /* Note we can mutate the buffer as we dup'd it */ + *lastslash = '\0'; + + if (!glnx_shutil_mkdir_p_at (dfd, path, mode, + cancellable, error)) + return FALSE; + + /* Now restore it for another mkdir attempt */ + *lastslash = '/'; + + did_recurse = TRUE; + goto again; + } + else if (errno == EEXIST) + { + /* Fall through; it may not have been a directory, + * but we'll find that out on the next call up. + */ + } + else + return glnx_throw_errno_prefix (error, "mkdir(%s)", path); + } + + return TRUE; +} + +/** + * glnx_shutil_mkdir_p_at: + * @dfd: Directory fd + * @path: Directory path to be created + * @mode: Mode for newly created directories + * @cancellable: Cancellable + * @error: Error + * + * Similar to g_mkdir_with_parents(), except operates relative to the + * directory fd @dfd. + * + * See also glnx_ensure_dir() for a non-recursive version. + * + * This will return %G_IO_ERROR_NOT_FOUND if @dfd has been deleted since being + * opened. It may return other errors from mkdirat() in other situations. + */ +gboolean +glnx_shutil_mkdir_p_at (int dfd, + const char *path, + int mode, + GCancellable *cancellable, + GError **error) +{ + struct stat stbuf; + char *buf; + + /* Fast path stat to see whether it already exists */ + if (fstatat (dfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) == 0) + { + /* Note early return */ + if (S_ISDIR (stbuf.st_mode)) + return TRUE; + } + + buf = strdupa (path); + + if (!mkdir_p_at_internal (dfd, buf, mode, cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * glnx_shutil_mkdir_p_at_open: + * @dfd: Directory fd + * @path: Directory path to be created + * @mode: Mode for newly created directories + * @out_dfd: (out caller-allocates): Return location for an FD to @dfd/@path, + * or `-1` on error + * @cancellable: (nullable): Cancellable, or %NULL + * @error: Return location for a #GError, or %NULL + * + * Similar to glnx_shutil_mkdir_p_at(), except it opens the resulting directory + * and returns a directory FD to it. Currently, this is not guaranteed to be + * race-free. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +gboolean +glnx_shutil_mkdir_p_at_open (int dfd, + const char *path, + int mode, + int *out_dfd, + GCancellable *cancellable, + GError **error) +{ + /* FIXME: It’s not possible to eliminate the race here until + * openat(O_DIRECTORY | O_CREAT) works (and returns a directory rather than a + * file). It appears to be not supported in current kernels. (Tested with + * 4.10.10-200.fc25.x86_64.) */ + *out_dfd = -1; + + if (!glnx_shutil_mkdir_p_at (dfd, path, mode, cancellable, error)) + return FALSE; + + return glnx_opendirat (dfd, path, TRUE, out_dfd, error); +} diff --git a/libglnx/glnx-shutil.h b/libglnx/glnx-shutil.h new file mode 100644 index 0000000..56a99fa --- /dev/null +++ b/libglnx/glnx-shutil.h @@ -0,0 +1,48 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean +glnx_shutil_rm_rf_at (int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_shutil_mkdir_p_at (int dfd, + const char *path, + int mode, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_shutil_mkdir_p_at_open (int dfd, + const char *path, + int mode, + int *out_dfd, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/libglnx/glnx-xattrs.c b/libglnx/glnx-xattrs.c new file mode 100644 index 0000000..79a14cd --- /dev/null +++ b/libglnx/glnx-xattrs.c @@ -0,0 +1,444 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include +#include + +static GVariant * +variant_new_ay_bytes (GBytes *bytes) +{ + gsize size; + gconstpointer data; + data = g_bytes_get_data (bytes, &size); + g_bytes_ref (bytes); + return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, size, + TRUE, (GDestroyNotify)g_bytes_unref, bytes); +} + +static char * +canonicalize_xattrs (char *xattr_string, + size_t len) +{ + char *p; + GSList *xattrs = NULL; + GSList *iter; + GString *result; + + result = g_string_new (0); + + p = xattr_string; + while (p < xattr_string+len) + { + xattrs = g_slist_prepend (xattrs, p); + p += strlen (p) + 1; + } + + xattrs = g_slist_sort (xattrs, (GCompareFunc) strcmp); + for (iter = xattrs; iter; iter = iter->next) { + g_string_append (result, iter->data); + g_string_append_c (result, '\0'); + } + + g_slist_free (xattrs); + return g_string_free (result, FALSE); +} + +static gboolean +read_xattr_name_array (const char *path, + int fd, + const char *xattrs, + size_t len, + GVariantBuilder *builder, + GError **error) +{ + gboolean ret = FALSE; + const char *p; + int r; + const char *funcstr; + + g_assert (path != NULL || fd != -1); + + funcstr = fd != -1 ? "fgetxattr" : "lgetxattr"; + + for (p = xattrs; p < xattrs+len; p = p + strlen (p) + 1) + { + ssize_t bytes_read; + g_autofree char *buf = NULL; + g_autoptr(GBytes) bytes = NULL; + + again: + if (fd != -1) + bytes_read = fgetxattr (fd, p, NULL, 0); + else + bytes_read = lgetxattr (path, p, NULL, 0); + if (bytes_read < 0) + { + if (errno == ENODATA) + continue; + + glnx_set_prefix_error_from_errno (error, "%s", funcstr); + goto out; + } + if (bytes_read == 0) + continue; + + buf = g_malloc (bytes_read); + if (fd != -1) + r = fgetxattr (fd, p, buf, bytes_read); + else + r = lgetxattr (path, p, buf, bytes_read); + if (r < 0) + { + if (errno == ERANGE) + { + g_free (g_steal_pointer (&buf)); + goto again; + } + else if (errno == ENODATA) + continue; + + glnx_set_prefix_error_from_errno (error, "%s", funcstr); + goto out; + } + + bytes = g_bytes_new_take (g_steal_pointer (&buf), bytes_read); + g_variant_builder_add (builder, "(@ay@ay)", + g_variant_new_bytestring (p), + variant_new_ay_bytes (bytes)); + } + + ret = TRUE; + out: + return ret; +} + +static gboolean +get_xattrs_impl (const char *path, + int fd, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + ssize_t bytes_read, real_size; + g_autofree char *xattr_names = NULL; + g_autofree char *xattr_names_canonical = NULL; + GVariantBuilder builder; + gboolean builder_initialized = FALSE; + g_autoptr(GVariant) ret_xattrs = NULL; + + g_assert (path != NULL || fd != -1); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)")); + builder_initialized = TRUE; + + again: + if (path) + bytes_read = llistxattr (path, NULL, 0); + else + bytes_read = flistxattr (fd, NULL, 0); + + if (bytes_read < 0) + { + if (errno != ENOTSUP) + { + glnx_set_prefix_error_from_errno (error, "%s", "llistxattr"); + goto out; + } + } + else if (bytes_read > 0) + { + xattr_names = g_malloc (bytes_read); + if (path) + real_size = llistxattr (path, xattr_names, bytes_read); + else + real_size = flistxattr (fd, xattr_names, bytes_read); + if (real_size < 0) + { + if (errno == ERANGE) + { + g_free (xattr_names); + goto again; + } + glnx_set_prefix_error_from_errno (error, "%s", "llistxattr"); + goto out; + } + else if (real_size > 0) + { + xattr_names_canonical = canonicalize_xattrs (xattr_names, real_size); + + if (!read_xattr_name_array (path, fd, xattr_names_canonical, real_size, &builder, error)) + goto out; + } + } + + ret_xattrs = g_variant_builder_end (&builder); + builder_initialized = FALSE; + g_variant_ref_sink (ret_xattrs); + + ret = TRUE; + if (out_xattrs) + *out_xattrs = g_steal_pointer (&ret_xattrs); + out: + if (!builder_initialized) + g_variant_builder_clear (&builder); + return ret; +} + +/** + * glnx_fd_get_all_xattrs: + * @fd: a file descriptor + * @out_xattrs: (out): A new #GVariant containing the extended attributes + * @cancellable: Cancellable + * @error: Error + * + * Read all extended attributes from @fd in a canonical sorted order, and + * set @out_xattrs with the result. + * + * If the filesystem does not support extended attributes, @out_xattrs + * will have 0 elements, and this function will return successfully. + */ +gboolean +glnx_fd_get_all_xattrs (int fd, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + return get_xattrs_impl (NULL, fd, out_xattrs, + cancellable, error); +} + +/** + * glnx_dfd_name_get_all_xattrs: + * @dfd: Parent directory file descriptor + * @name: File name + * @out_xattrs: (out): Extended attribute set + * @cancellable: Cancellable + * @error: Error + * + * Load all extended attributes for the file named @name residing in + * directory @dfd. + */ +gboolean +glnx_dfd_name_get_all_xattrs (int dfd, + const char *name, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + if (G_IN_SET(dfd, AT_FDCWD, -1)) + { + return get_xattrs_impl (name, -1, out_xattrs, cancellable, error); + } + else + { + char buf[PATH_MAX]; + /* A workaround for the lack of lgetxattrat(), thanks to Florian Weimer: + * https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html + */ + snprintf (buf, sizeof (buf), "/proc/self/fd/%d/%s", dfd, name); + return get_xattrs_impl (buf, -1, out_xattrs, cancellable, error); + } +} + +static gboolean +set_all_xattrs_for_path (const char *path, + GVariant *xattrs, + GCancellable *cancellable, + GError **error) +{ + const guint n = g_variant_n_children (xattrs); + for (guint i = 0; i < n; i++) + { + const guint8* name; + g_autoptr(GVariant) value = NULL; + g_variant_get_child (xattrs, i, "(^&ay@ay)", + &name, &value); + + gsize value_len; + const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1); + + if (lsetxattr (path, (char*)name, (char*)value_data, value_len, 0) < 0) + return glnx_throw_errno_prefix (error, "lsetxattr"); + } + + return TRUE; +} + +/** + * glnx_dfd_name_set_all_xattrs: + * @dfd: Parent directory file descriptor + * @name: File name + * @xattrs: Extended attribute set + * @cancellable: Cancellable + * @error: Error + * + * Set all extended attributes for the file named @name residing in + * directory @dfd. + */ +gboolean +glnx_dfd_name_set_all_xattrs (int dfd, + const char *name, + GVariant *xattrs, + GCancellable *cancellable, + GError **error) +{ + if (G_IN_SET(dfd, AT_FDCWD, -1)) + { + return set_all_xattrs_for_path (name, xattrs, cancellable, error); + } + else + { + char buf[PATH_MAX]; + /* A workaround for the lack of lsetxattrat(), thanks to Florian Weimer: + * https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html + */ + snprintf (buf, sizeof (buf), "/proc/self/fd/%d/%s", dfd, name); + return set_all_xattrs_for_path (buf, xattrs, cancellable, error); + } +} + +/** + * glnx_fd_set_all_xattrs: + * @fd: File descriptor + * @xattrs: Extended attributes + * @cancellable: Cancellable + * @error: Error + * + * For each attribute in @xattrs, set its value on the file or + * directory referred to by @fd. This function does not remove any + * attributes not in @xattrs. + */ +gboolean +glnx_fd_set_all_xattrs (int fd, + GVariant *xattrs, + GCancellable *cancellable, + GError **error) +{ + const guint n = g_variant_n_children (xattrs); + for (guint i = 0; i < n; i++) + { + const guint8* name; + g_autoptr(GVariant) value = NULL; + g_variant_get_child (xattrs, i, "(^&ay@ay)", + &name, &value); + + gsize value_len; + const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1); + + if (TEMP_FAILURE_RETRY (fsetxattr (fd, (char*)name, (char*)value_data, value_len, 0)) < 0) + return glnx_throw_errno_prefix (error, "fsetxattr"); + } + + return TRUE; +} + +/** + * glnx_lgetxattrat: + * @dfd: Directory file descriptor + * @subpath: Subpath + * @attribute: Extended attribute to retrieve + * @error: Error + * + * Retrieve an extended attribute value, relative to a directory file + * descriptor. + */ +GBytes * +glnx_lgetxattrat (int dfd, + const char *subpath, + const char *attribute, + GError **error) +{ + char pathbuf[PATH_MAX]; + snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", dfd, subpath); + + ssize_t bytes_read, real_size; + if (TEMP_FAILURE_RETRY (bytes_read = lgetxattr (pathbuf, attribute, NULL, 0)) < 0) + return glnx_null_throw_errno_prefix (error, "lgetxattr"); + + g_autofree guint8 *buf = g_malloc (bytes_read); + if (TEMP_FAILURE_RETRY (real_size = lgetxattr (pathbuf, attribute, buf, bytes_read)) < 0) + return glnx_null_throw_errno_prefix (error, "lgetxattr"); + + return g_bytes_new_take (g_steal_pointer (&buf), real_size); +} + +/** + * glnx_fgetxattr_bytes: + * @fd: Directory file descriptor + * @attribute: Extended attribute to retrieve + * @error: Error + * + * Returns: (transfer full): An extended attribute value, or %NULL on error + */ +GBytes * +glnx_fgetxattr_bytes (int fd, + const char *attribute, + GError **error) +{ + ssize_t bytes_read, real_size; + + if (TEMP_FAILURE_RETRY (bytes_read = fgetxattr (fd, attribute, NULL, 0)) < 0) + return glnx_null_throw_errno_prefix (error, "fgetxattr"); + + g_autofree guint8 *buf = g_malloc (bytes_read); + if (TEMP_FAILURE_RETRY (real_size = fgetxattr (fd, attribute, buf, bytes_read)) < 0) + return glnx_null_throw_errno_prefix (error, "fgetxattr"); + + return g_bytes_new_take (g_steal_pointer (&buf), real_size); +} + +/** + * glnx_lsetxattrat: + * @dfd: Directory file descriptor + * @subpath: Path + * @attribute: An attribute name + * @value: (array length=len) (element-type guint8): Attribute value + * @len: Length of @value + * @flags: Flags, containing either XATTR_CREATE or XATTR_REPLACE + * @error: Error + * + * Set an extended attribute, relative to a directory file descriptor. + */ +gboolean +glnx_lsetxattrat (int dfd, + const char *subpath, + const char *attribute, + const guint8 *value, + gsize len, + int flags, + GError **error) +{ + char pathbuf[PATH_MAX]; + snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", dfd, subpath); + + if (TEMP_FAILURE_RETRY (lsetxattr (subpath, attribute, value, len, flags)) < 0) + return glnx_throw_errno_prefix (error, "lsetxattr"); + + return TRUE; +} + diff --git a/libglnx/glnx-xattrs.h b/libglnx/glnx-xattrs.h new file mode 100644 index 0000000..a566a22 --- /dev/null +++ b/libglnx/glnx-xattrs.h @@ -0,0 +1,78 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +gboolean +glnx_dfd_name_get_all_xattrs (int dfd, + const char *name, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_fd_get_all_xattrs (int fd, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_dfd_name_set_all_xattrs (int dfd, + const char *name, + GVariant *xattrs, + GCancellable *cancellable, + GError **error); + +gboolean +glnx_fd_set_all_xattrs (int fd, + GVariant *xattrs, + GCancellable *cancellable, + GError **error); + +GBytes * +glnx_lgetxattrat (int dfd, + const char *subpath, + const char *attribute, + GError **error); + +GBytes * +glnx_fgetxattr_bytes (int fd, + const char *attribute, + GError **error); + +gboolean +glnx_lsetxattrat (int dfd, + const char *subpath, + const char *attribute, + const guint8 *value, + gsize len, + int flags, + GError **error); + +G_END_DECLS diff --git a/libglnx/libglnx.h b/libglnx/libglnx.h new file mode 100644 index 0000000..411d4fa --- /dev/null +++ b/libglnx/libglnx.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2012,2013,2015 Colin Walters . + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +G_END_DECLS diff --git a/libglnx/libglnx.m4 b/libglnx/libglnx.m4 new file mode 100644 index 0000000..5a72e98 --- /dev/null +++ b/libglnx/libglnx.m4 @@ -0,0 +1,34 @@ +AC_DEFUN([LIBGLNX_CONFIGURE], +[ +AC_CHECK_DECLS([ + renameat2, + memfd_create, + copy_file_range], + [], [], [[ +#include +#include +#include +#include +#include +#include +#include +#include +#include +]]) + +AC_ARG_ENABLE(otmpfile, + [AS_HELP_STRING([--disable-otmpfile], + [Disable use of O_TMPFILE [default=no]])],, + [enable_otmpfile=yes]) +AS_IF([test $enable_otmpfile = yes], [], [ + AC_DEFINE([DISABLE_OTMPFILE], 1, [Define if we should avoid using O_TMPFILE])]) + +AC_ARG_ENABLE(wrpseudo-compat, + [AS_HELP_STRING([--enable-wrpseudo-compat], + [Disable use of syscall() in some cases for compatibility with pseudo [default=no]])],, + [enable_wrpseudo_compat=no]) +AS_IF([test $enable_wrpseudo_compat = no], [], [ + AC_DEFINE([ENABLE_WRPSEUDO_COMPAT], 1, [Define if we should be compatible with pseudo])]) + +dnl end LIBGLNX_CONFIGURE +]) diff --git a/libglnx/tests/libglnx-testlib.c b/libglnx/tests/libglnx-testlib.c new file mode 100644 index 0000000..869d144 --- /dev/null +++ b/libglnx/tests/libglnx-testlib.c @@ -0,0 +1,74 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright 2019 Collabora Ltd. + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx-testlib.h" + +#include + +#include + +#include "libglnx.h" + +struct _GLnxTestAutoTempDir +{ + gchar *old_cwd; + int old_cwd_fd; + GLnxTmpDir temp_dir; +}; + +_GLnxTestAutoTempDir * +_glnx_test_auto_temp_dir_enter (void) +{ + GError *error = NULL; + _GLnxTestAutoTempDir *ret = g_new0 (_GLnxTestAutoTempDir, 1); + + glnx_mkdtemp ("glnx-test-XXXXXX", 0700, &ret->temp_dir, &error); + g_assert_no_error (error); + + /* just for better diagnostics */ + ret->old_cwd = g_get_current_dir (); + + glnx_opendirat (-1, ".", TRUE, &ret->old_cwd_fd, &error); + g_assert_no_error (error); + + if (fchdir (ret->temp_dir.fd) != 0) + g_error ("fchdir(): %s", ret->temp_dir.path, g_strerror (errno)); + + return ret; +} + +void +_glnx_test_auto_temp_dir_leave (_GLnxTestAutoTempDir *dir) +{ + GError *error = NULL; + + if (fchdir (dir->old_cwd_fd) != 0) + g_error ("fchdir(): %s", dir->old_cwd, g_strerror (errno)); + + glnx_tmpdir_delete (&dir->temp_dir, NULL, &error); + g_assert_no_error (error); + + g_close (dir->old_cwd_fd, &error); + g_assert_no_error (error); + + g_free (dir->old_cwd); + g_free (dir); +} diff --git a/libglnx/tests/libglnx-testlib.h b/libglnx/tests/libglnx-testlib.h new file mode 100644 index 0000000..d45ba86 --- /dev/null +++ b/libglnx/tests/libglnx-testlib.h @@ -0,0 +1,48 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * Copyright 2019 Collabora Ltd. + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +#include "glnx-backport-autoptr.h" + +typedef GError _GLnxTestAutoError; +static inline void +_glnx_test_auto_error_cleanup (_GLnxTestAutoError *autoerror) +{ + g_assert_no_error (autoerror); + /* We could add a clear call here, but no point...we'll have aborted */ +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC(_GLnxTestAutoError, _glnx_test_auto_error_cleanup); + +#define _GLNX_TEST_DECLARE_ERROR(local_error, error) \ + g_autoptr(_GLnxTestAutoError) local_error = NULL; \ + GError **error = &local_error + +typedef struct _GLnxTestAutoTempDir _GLnxTestAutoTempDir; + +_GLnxTestAutoTempDir *_glnx_test_auto_temp_dir_enter (void); +void _glnx_test_auto_temp_dir_leave (_GLnxTestAutoTempDir *dir); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(_GLnxTestAutoTempDir, _glnx_test_auto_temp_dir_leave); + +#define _GLNX_TEST_SCOPED_TEMP_DIR \ + G_GNUC_UNUSED g_autoptr(_GLnxTestAutoTempDir) temp_dir = _glnx_test_auto_temp_dir_enter () diff --git a/libglnx/tests/test-libglnx-errors.c b/libglnx/tests/test-libglnx-errors.c new file mode 100644 index 0000000..4e91e02 --- /dev/null +++ b/libglnx/tests/test-libglnx-errors.c @@ -0,0 +1,183 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include + +static void +test_error_throw (void) +{ + g_autoptr(GError) error = NULL; + + g_assert (!glnx_throw (&error, "foo: %s %d", "hello", 42)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_assert_cmpstr (error->message, ==, "foo: hello 42"); + g_clear_error (&error); + + gpointer dummy = glnx_null_throw (&error, "literal foo"); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_assert_cmpstr (error->message, ==, "literal foo"); + g_clear_error (&error); + + gpointer dummy2 = glnx_null_throw (&error, "foo: %s %d", "hola", 24); + g_assert (dummy2 == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_assert_cmpstr (error->message, ==, "foo: hola 24"); + g_clear_error (&error); +} + +static void +test_error_errno (void) +{ + g_autoptr(GError) error = NULL; + const char noent_path[] = "/enoent-this-should-not-exist"; + int fd; + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + g_assert (!glnx_throw_errno (&error)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (!glnx_prefix_error (&error, "myprefix")); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, "myprefix: ")); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + gpointer dummy = glnx_null_throw_errno (&error); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + dummy = glnx_prefix_error_null (&error, "myprefix"); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, "myprefix: ")); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + g_autofree char *expected_prefix = g_strdup_printf ("Failed to open %s", noent_path); + g_assert (!glnx_throw_errno_prefix (&error, "Failed to open %s", noent_path)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, expected_prefix)); + g_clear_error (&error); + /* And test the legacy wrapper */ + glnx_set_prefix_error_from_errno (&error, "Failed to open %s", noent_path); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, expected_prefix)); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + gpointer dummy = glnx_null_throw_errno_prefix (&error, "Failed to open file"); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, "Failed to open file")); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + gpointer dummy = glnx_null_throw_errno_prefix (&error, "Failed to open %s", noent_path); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, glnx_strjoina ("Failed to open ", noent_path))); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); +} + +static void +test_error_auto_nothrow (GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("foo", error); + /* Side effect to avoid otherwise empty function */ + g_assert_no_error (*error); +} + +static void +test_error_auto_throw (GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("foo", error); + (void) glnx_throw (error, "oops"); +} + +static void +test_error_auto_throw_recurse (GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("foo", error); + + if (TRUE) + { + GLNX_AUTO_PREFIX_ERROR("bar", error); + (void) glnx_throw (error, "oops"); + } +} + +static void +test_error_auto (void) +{ + g_autoptr(GError) error = NULL; + test_error_auto_nothrow (&error); + g_assert_no_error (error); + test_error_auto_throw (&error); + g_assert_nonnull (error); + g_assert_cmpstr (error->message, ==, "foo: oops"); + g_clear_error (&error); + test_error_auto_throw_recurse (&error); + g_assert_nonnull (error); + g_assert_cmpstr (error->message, ==, "foo: bar: oops"); +} + +int main (int argc, char **argv) +{ + int ret; + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/error-throw", test_error_throw); + g_test_add_func ("/error-errno", test_error_errno); + g_test_add_func ("/error-auto", test_error_auto); + + ret = g_test_run(); + + return ret; +} diff --git a/libglnx/tests/test-libglnx-fdio.c b/libglnx/tests/test-libglnx-fdio.c new file mode 100644 index 0000000..84ebb14 --- /dev/null +++ b/libglnx/tests/test-libglnx-fdio.c @@ -0,0 +1,255 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include +#include + +#include "libglnx-testlib.h" + +static gboolean +renameat_test_setup (int *out_srcfd, int *out_destfd, + GError **error) +{ + glnx_autofd int srcfd = -1; + glnx_autofd int destfd = -1; + + (void) glnx_shutil_rm_rf_at (AT_FDCWD, "srcdir", NULL, NULL); + if (mkdir ("srcdir", 0755) < 0) + err (1, "mkdir"); + if (!glnx_opendirat (AT_FDCWD, "srcdir", TRUE, &srcfd, error)) + return FALSE; + (void) glnx_shutil_rm_rf_at (AT_FDCWD, "destdir", NULL, NULL); + if (mkdir ("destdir", 0755) < 0) + err (1, "mkdir"); + if (!glnx_opendirat (AT_FDCWD, "destdir", TRUE, &destfd, error)) + return FALSE; + + if (!glnx_file_replace_contents_at (srcfd, "foo", (guint8*)"foo contents", strlen ("foo contents"), + GLNX_FILE_REPLACE_NODATASYNC, NULL, error)) + return FALSE; + if (!glnx_file_replace_contents_at (destfd, "bar", (guint8*)"bar contents", strlen ("bar contents"), + GLNX_FILE_REPLACE_NODATASYNC, NULL, error)) + return FALSE; + + *out_srcfd = srcfd; srcfd = -1; + *out_destfd = destfd; destfd = -1; + return TRUE; +} + +static void +test_renameat2_noreplace (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + glnx_autofd int srcfd = -1; + glnx_autofd int destfd = -1; + struct stat stbuf; + + if (!renameat_test_setup (&srcfd, &destfd, error)) + return; + + if (glnx_renameat2_noreplace (srcfd, "foo", destfd, "bar") == 0) + g_assert_not_reached (); + else + { + g_assert_cmpint (errno, ==, EEXIST); + } + + if (glnx_renameat2_noreplace (srcfd, "foo", destfd, "baz") < 0) + return (void)glnx_throw_errno_prefix (error, "renameat"); + if (!glnx_fstatat (destfd, "bar", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + + if (fstatat (srcfd, "foo", &stbuf, AT_SYMLINK_NOFOLLOW) == 0) + g_assert_not_reached (); + else + g_assert_cmpint (errno, ==, ENOENT); +} + +static void +test_renameat2_exchange (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + + glnx_autofd int srcfd = -1; + glnx_autofd int destfd = -1; + if (!renameat_test_setup (&srcfd, &destfd, error)) + return; + + if (glnx_renameat2_exchange (AT_FDCWD, "srcdir", AT_FDCWD, "destdir") < 0) + return (void)glnx_throw_errno_prefix (error, "renameat"); + + /* Ensure the dir fds are the same */ + struct stat stbuf; + if (!glnx_fstatat (srcfd, "foo", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + if (!glnx_fstatat (destfd, "bar", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + /* But the dirs should be swapped */ + if (!glnx_fstatat (AT_FDCWD, "destdir/foo", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + if (!glnx_fstatat (AT_FDCWD, "srcdir/bar", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; +} + +static void +test_tmpfile (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, ".", O_WRONLY|O_CLOEXEC, &tmpf, error)) + return; + if (glnx_loop_write (tmpf.fd, "foo", strlen ("foo")) < 0) + return (void)glnx_throw_errno_prefix (error, "write"); + if (glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_NOREPLACE, AT_FDCWD, "foo", error)) + return; +} + +static void +test_stdio_file (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + g_auto(GLnxTmpfile) tmpf = { 0, }; + g_autoptr(FILE) f = NULL; + + if (!glnx_open_anonymous_tmpfile (O_RDWR|O_CLOEXEC, &tmpf, error)) + return; + f = fdopen (tmpf.fd, "w"); + tmpf.fd = -1; /* Ownership was transferred via fdopen() */ + if (!f) + return (void)glnx_throw_errno_prefix (error, "fdopen"); + if (fwrite ("hello", 1, strlen ("hello"), f) != strlen ("hello")) + return (void)glnx_throw_errno_prefix (error, "fwrite"); + if (!glnx_stdio_file_flush (f, error)) + return; +} + +static void +test_fstatat (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + struct stat stbuf = { 0, }; + + if (!glnx_fstatat_allow_noent (AT_FDCWD, ".", &stbuf, 0, error)) + return; + g_assert_cmpint (errno, ==, 0); + g_assert_no_error (local_error); + g_assert (S_ISDIR (stbuf.st_mode)); + if (!glnx_fstatat_allow_noent (AT_FDCWD, "nosuchfile", &stbuf, 0, error)) + return; + g_assert_cmpint (errno, ==, ENOENT); + g_assert_no_error (local_error); + + /* test NULL parameter for stat */ + if (!glnx_fstatat_allow_noent (AT_FDCWD, ".", NULL, 0, error)) + return; + g_assert_cmpint (errno, ==, 0); + g_assert_no_error (local_error); + if (!glnx_fstatat_allow_noent (AT_FDCWD, "nosuchfile", NULL, 0, error)) + return; + g_assert_cmpint (errno, ==, ENOENT); + g_assert_no_error (local_error); +} + +static void +test_filecopy (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + const char foo[] = "foo"; + struct stat stbuf; + + if (!glnx_ensure_dir (AT_FDCWD, "subdir", 0755, error)) + return; + + if (!glnx_file_replace_contents_at (AT_FDCWD, foo, (guint8*)foo, sizeof (foo), + GLNX_FILE_REPLACE_NODATASYNC, NULL, error)) + return; + + /* Copy it into both the same dir and a subdir */ + if (!glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "bar", + GLNX_FILE_COPY_NOXATTRS, NULL, error)) + return; + if (!glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "subdir/bar", + GLNX_FILE_COPY_NOXATTRS, NULL, error)) + return; + if (!glnx_fstatat (AT_FDCWD, "subdir/bar", &stbuf, 0, error)) + return; + + if (glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "bar", + GLNX_FILE_COPY_NOXATTRS, NULL, error)) + g_assert_not_reached (); + g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS); + g_clear_error (&local_error); + + if (!glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "bar", + GLNX_FILE_COPY_NOXATTRS | GLNX_FILE_COPY_OVERWRITE, + NULL, error)) + return; + + if (symlinkat ("nosuchtarget", AT_FDCWD, "link") < 0) + return (void) glnx_throw_errno_prefix (error, "symlinkat"); + + /* Shouldn't be able to overwrite a symlink without GLNX_FILE_COPY_OVERWRITE */ + if (glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "link", + GLNX_FILE_COPY_NOXATTRS, + NULL, error)) + g_assert_not_reached (); + g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS); + g_clear_error (&local_error); + + /* Test overwriting symlink */ + if (!glnx_file_copy_at (AT_FDCWD, foo, NULL, AT_FDCWD, "link", + GLNX_FILE_COPY_NOXATTRS | GLNX_FILE_COPY_OVERWRITE, + NULL, error)) + return; + + if (!glnx_fstatat_allow_noent (AT_FDCWD, "nosuchtarget", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + g_assert_cmpint (errno, ==, ENOENT); + g_assert_no_error (local_error); + + if (!glnx_fstatat (AT_FDCWD, "link", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return; + g_assert (S_ISREG (stbuf.st_mode)); +} + +int main (int argc, char **argv) +{ + _GLNX_TEST_SCOPED_TEMP_DIR; + int ret; + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/tmpfile", test_tmpfile); + g_test_add_func ("/stdio-file", test_stdio_file); + g_test_add_func ("/filecopy", test_filecopy); + g_test_add_func ("/renameat2-noreplace", test_renameat2_noreplace); + g_test_add_func ("/renameat2-exchange", test_renameat2_exchange); + g_test_add_func ("/fstat", test_fstatat); + + ret = g_test_run(); + + return ret; +} diff --git a/libglnx/tests/test-libglnx-macros.c b/libglnx/tests/test-libglnx-macros.c new file mode 100644 index 0000000..ffde8fa --- /dev/null +++ b/libglnx/tests/test-libglnx-macros.c @@ -0,0 +1,109 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include + +static void +test_inset (void) +{ + g_assert (G_IN_SET (7, 7)); + g_assert (G_IN_SET (7, 42, 7)); + g_assert (G_IN_SET (7, 7,42,3,9)); + g_assert (G_IN_SET (42, 7,42,3,9)); + g_assert (G_IN_SET (3, 7,42,3,9)); + g_assert (G_IN_SET (9, 7,42,3,9)); + g_assert (!G_IN_SET (8, 7,42,3,9)); + g_assert (!G_IN_SET (-1, 7,42,3,9)); + g_assert (G_IN_SET ('x', 'a', 'x', 'c')); + g_assert (!G_IN_SET ('y', 'a', 'x', 'c')); +} + +static void +test_hash_table_foreach (void) +{ + /* use var names all different from the macro metavars to ensure proper + * substitution */ + g_autoptr(GHashTable) table = g_hash_table_new (g_str_hash, g_str_equal); + const char *keys[] = {"key1", "key2"}; + const char *vals[] = {"val1", "val2"}; + g_hash_table_insert (table, (gpointer)keys[0], (gpointer)vals[0]); + g_hash_table_insert (table, (gpointer)keys[1], (gpointer)vals[1]); + + guint i = 0; + GLNX_HASH_TABLE_FOREACH_IT (table, it, const char*, key, const char*, val) + { + g_assert_cmpstr (key, ==, keys[i]); + g_assert_cmpstr (val, ==, vals[i]); + i++; + } + g_assert_cmpuint (i, ==, 2); + + i = 0; + GLNX_HASH_TABLE_FOREACH_IT (table, it, const char*, key, const char*, val) + { + g_hash_table_iter_remove (&it); + break; + } + g_assert_cmpuint (g_hash_table_size (table), ==, 1); + + g_hash_table_insert (table, (gpointer)keys[1], (gpointer)vals[1]); + g_assert_cmpuint (g_hash_table_size (table), ==, 1); + + g_hash_table_insert (table, (gpointer)keys[0], (gpointer)vals[0]); + g_assert_cmpuint (g_hash_table_size (table), ==, 2); + + i = 0; + GLNX_HASH_TABLE_FOREACH_KV (table, const char*, key, const char*, val) + { + g_assert_cmpstr (key, ==, keys[i]); + g_assert_cmpstr (val, ==, vals[i]); + i++; + } + g_assert_cmpuint (i, ==, 2); + + i = 0; + GLNX_HASH_TABLE_FOREACH (table, const char*, key) + { + g_assert_cmpstr (key, ==, keys[i]); + i++; + } + g_assert_cmpuint (i, ==, 2); + + i = 0; + GLNX_HASH_TABLE_FOREACH_V (table, const char*, val) + { + g_assert_cmpstr (val, ==, vals[i]); + i++; + } + g_assert_cmpuint (i, ==, 2); +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/inset", test_inset); + g_test_add_func ("/hash_table_foreach", test_hash_table_foreach); + return g_test_run(); +} diff --git a/libglnx/tests/test-libglnx-shutil.c b/libglnx/tests/test-libglnx-shutil.c new file mode 100644 index 0000000..6917b89 --- /dev/null +++ b/libglnx/tests/test-libglnx-shutil.c @@ -0,0 +1,63 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright © 2017 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include +#include + +#include "libglnx-testlib.h" + +static void +test_mkdir_p_enoent (void) +{ + _GLNX_TEST_DECLARE_ERROR(local_error, error); + glnx_autofd int dfd = -1; + + if (!glnx_ensure_dir (AT_FDCWD, "test", 0755, error)) + return; + if (!glnx_opendirat (AT_FDCWD, "test", FALSE, &dfd, error)) + return; + if (rmdir ("test") < 0) + return (void) glnx_throw_errno_prefix (error, "rmdir(%s)", "test"); + + /* This should fail with ENOENT. */ + glnx_shutil_mkdir_p_at (dfd, "blah/baz", 0755, NULL, error); + g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_clear_error (&local_error); +} + +int +main (int argc, + char **argv) +{ + int ret; + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/mkdir-p/enoent", test_mkdir_p_enoent); + + ret = g_test_run(); + + return ret; +} diff --git a/libglnx/tests/test-libglnx-xattrs.c b/libglnx/tests/test-libglnx-xattrs.c new file mode 100644 index 0000000..82def4a --- /dev/null +++ b/libglnx/tests/test-libglnx-xattrs.c @@ -0,0 +1,287 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2017 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include + +#define XATTR_THREAD_RUN_TIME_USECS (5 * G_USEC_PER_SEC) + +struct XattrWorker { + int dfd; + gboolean is_writer; + guint n_attrs_read; +}; + +typedef enum { + WRITE_RUN_MUTATE, + WRITE_RUN_CREATE, +} WriteType; + +static gboolean +set_random_xattr_value (int fd, const char *name, GError **error) +{ + const guint8 randxattrbyte = g_random_int_range (0, 256); + const guint32 randxattrvalue_len = (g_random_int () % 256) + 1; /* Picked to be not too small or large */ + g_autofree char *randxattrvalue = g_malloc (randxattrvalue_len); + + memset (randxattrvalue, randxattrbyte, randxattrvalue_len); + + if (fsetxattr (fd, name, randxattrvalue, randxattrvalue_len, 0) < 0) + { + glnx_set_error_from_errno (error); + return FALSE; + } + + return TRUE; +} + +static gboolean +add_random_xattrs (int fd, GError **error) +{ + const guint nattrs = MIN (2, g_random_int () % 16); + + for (guint i = 0; i < nattrs; i++) + { + guint32 randxattrname_v = g_random_int (); + g_autofree char *randxattrname = g_strdup_printf ("user.test%u", randxattrname_v); + + if (!set_random_xattr_value (fd, randxattrname, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +do_write_run (GLnxDirFdIterator *dfd_iter, GError **error) +{ + WriteType wtype = g_random_int () % 2; + + if (wtype == WRITE_RUN_CREATE) + { + guint32 randname_v = g_random_int (); + g_autofree char *randname = g_strdup_printf ("file%u", randname_v); + glnx_autofd int fd = -1; + + again: + fd = openat (dfd_iter->fd, randname, O_CREAT | O_EXCL, 0644); + if (fd < 0) + { + if (errno == EEXIST) + { + g_printerr ("Congratulations! I suggest purchasing a lottery ticket today!\n"); + goto again; + } + else + { + glnx_set_error_from_errno (error); + return FALSE; + } + } + + if (!add_random_xattrs (fd, error)) + return FALSE; + } + else if (wtype == WRITE_RUN_MUTATE) + { + while (TRUE) + { + struct dirent *dent; + if (!glnx_dirfd_iterator_next_dent (dfd_iter, &dent, NULL, error)) + return FALSE; + if (!dent) + break; + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd_iter->fd, dent->d_name, FALSE, &fd, error)) + return FALSE; + + g_autoptr(GVariant) current_xattrs = NULL; + if (!glnx_fd_get_all_xattrs (fd, ¤t_xattrs, NULL, error)) + return FALSE; + + for (int i = 0; i < g_variant_n_children (current_xattrs); i++) + { + const char *name, *value; + g_variant_get_child (current_xattrs, i, "(^&ay^&ay)", &name, &value); + + /* We don't want to potentially test/change xattrs like security.selinux + * that were injected by the system. + */ + if (!g_str_has_prefix (name, "user.test")) + continue; + + if (!set_random_xattr_value (fd, name, error)) + return FALSE; + } + } + } + else + g_assert_not_reached (); + + return TRUE; +} + +static gboolean +do_read_run (GLnxDirFdIterator *dfd_iter, + guint *out_n_read, + GError **error) +{ + guint nattrs = 0; + while (TRUE) + { + struct dirent *dent; + if (!glnx_dirfd_iterator_next_dent (dfd_iter, &dent, NULL, error)) + return FALSE; + if (!dent) + break; + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd_iter->fd, dent->d_name, FALSE, &fd, error)) + return FALSE; + + g_autoptr(GVariant) current_xattrs = NULL; + if (!glnx_fd_get_all_xattrs (fd, ¤t_xattrs, NULL, error)) + return FALSE; + + /* We don't actually care about the values, just use the variable + * to avoid compiler warnings. + */ + nattrs += g_variant_n_children (current_xattrs); + } + + *out_n_read = nattrs; + return TRUE; +} + +static gpointer +xattr_thread (gpointer data) +{ + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + struct XattrWorker *worker = data; + guint64 end_time = g_get_monotonic_time () + XATTR_THREAD_RUN_TIME_USECS; + guint n_read = 0; + + while (g_get_monotonic_time () < end_time) + { + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + + if (!glnx_dirfd_iterator_init_at (worker->dfd, ".", TRUE, &dfd_iter, error)) + goto out; + + if (worker->is_writer) + { + if (!do_write_run (&dfd_iter, error)) + goto out; + } + else + { + if (!do_read_run (&dfd_iter, &n_read, error)) + goto out; + } + } + + out: + g_assert_no_error (local_error); + + return GINT_TO_POINTER (n_read); +} + +static void +test_xattr_races (void) +{ + /* If for some reason we're built in a VM which only has one vcpu, let's still + * at least make the test do something. + */ + /* FIXME - this deadlocks for me on 4.9.4-201.fc25.x86_64, whether + * using overlayfs or xfs as source/dest. + */ +#if GLIB_CHECK_VERSION (2, 36, 0) + const guint nprocs = MAX (4, g_get_num_processors ()); +#else + const guint nprocs = 4; +#endif + struct XattrWorker wdata[nprocs]; + GThread *threads[nprocs]; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + g_auto(GLnxTmpDir) tmpdir = { 0, }; + g_autofree char *tmpdir_path = g_strdup_printf ("%s/libglnx-xattrs-XXXXXX", + getenv ("TMPDIR") ?: "/var/tmp"); + guint nread = 0; + + if (!glnx_mkdtempat (AT_FDCWD, tmpdir_path, 0700, + &tmpdir, error)) + goto out; + + /* Support people building/testing on tmpfs https://github.com/flatpak/flatpak/issues/686 */ + if (fsetxattr (tmpdir.fd, "user.test", "novalue", strlen ("novalue"), 0) < 0) + { + if (errno == EOPNOTSUPP) + { + g_test_skip ("no xattr support"); + return; + } + else + { + glnx_set_error_from_errno (error); + goto out; + } + } + + for (guint i = 0; i < nprocs; i++) + { + struct XattrWorker *worker = &wdata[i]; + worker->dfd = tmpdir.fd; + worker->is_writer = i % 2 == 0; + threads[i] = g_thread_new (NULL, xattr_thread, worker); + } + + for (guint i = 0; i < nprocs; i++) + { + if (wdata[i].is_writer) + (void) g_thread_join (threads[i]); + else + nread += GPOINTER_TO_UINT (g_thread_join (threads[i])); + } + + g_print ("Read %u xattrs race free!\n", nread); + + out: + g_assert_no_error (local_error); +} + +int main (int argc, char **argv) +{ + int ret; + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/xattr-races", test_xattr_races); + + ret = g_test_run(); + + return ret; +} diff --git a/man/ostree-admin-cleanup.xml b/man/ostree-admin-cleanup.xml new file mode 100644 index 0000000..b7dfb65 --- /dev/null +++ b/man/ostree-admin-cleanup.xml @@ -0,0 +1,70 @@ + + + + + + + + + ostree admin cleanup + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin cleanup + 1 + + + + ostree-admin-cleanup + Delete untagged deployments and repository objects + + + + + ostree admin cleanup + + + + + Description + + + OSTree sysroot cleans up other bootversions and old deployments. If/when a pull or deployment is interrupted, a partially written state may remain on disk. This command cleans up any such partial states. + + + + + Example + $ ostree admin cleanup + + diff --git a/man/ostree-admin-config-diff.xml b/man/ostree-admin-config-diff.xml new file mode 100644 index 0000000..b1c8173 --- /dev/null +++ b/man/ostree-admin-config-diff.xml @@ -0,0 +1,88 @@ + + + + + + + + + ostree admin config-diff + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin config-diff + 1 + + + + ostree-admin-config-diff + Diff current /etc configuration versus default + + + + + ostree admin config-diff OPTIONS + + + + + Description + + + Prints the differences between the current /etc directory and the default configuration in /usr/etc. Newly added files (present in /etc but not in /usr/etc) will be prefixed with 'A'. Modified files will be prefixed with 'M', and deleted files with 'D'. + + + + + Options + + + + ="STATEROOT" + + + Use a different operating system stateroot than the current one. + + + + + + + Example + $ ostree admin config-diff + + M shadow + A example.txt + + + diff --git a/man/ostree-admin-deploy.xml b/man/ostree-admin-deploy.xml new file mode 100644 index 0000000..396d901 --- /dev/null +++ b/man/ostree-admin-deploy.xml @@ -0,0 +1,170 @@ + + + + + + + + + ostree admin deploy + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin deploy + 1 + + + + ostree-admin-deploy + Checkout a revision as the new default deployment + + + + + ostree admin deploy OPTIONS REFSPEC + + + + + Description + + + Takes a commit or revision REFSPEC, and queues the new deployment as default upon reboot. + + + + + Options + + + + ="STATEROOT" + + + Use a different operating system root than the current one. + + + + + ="FILENAME" + + + Use FILENAME as the origin, which is where OSTree will look for updated versions of the tree. + + + + + + + + Do not delete previous deployment. + + + + + + + + Do not delete pending deployments. + + + + + + + + Do not delete rollback deployments. + + + + + + + + Append rather than prepend new deployment. + + + + + + + + Import current /proc/cmdline. + + + + + ="NAME=VALUE" + + + Set kernel argument, like root=/dev/sda1; this overrides any earlier argument with the same name. + + + + + ="NAME=VALUE" + + + Append kernel argument; useful with e.g. console= that can be used multiple times. + + + + + + + Example + $ ostree admin status + + * gnome-ostree 67e382b11d213a402a5313e61cbc69dfd5ab93cb07.0 + origin refspec: gnome-ostree/buildmaster/x86_64-runtime + gnome-ostree ce19c41036cc45e49b0cecf6b157523c2105c4de1ce3.0 + origin refspec: gnome-ostree/buildmaster/x86_64-runtime + + +$ ostree admin deploy gnome-ostree/buildmaster/x86_64-runtime + + ostadmin: Creating deployment /ostree/deploy/gnome-ostree/deploy/7e382b11d213a402a5313e61cbc69dfd5ab93cb07.1 + ostadmin: Processing /etc: 3 modified, 0 removed, 29 added + Transaction complete: bootconfig swap: no deployment count change: 0) + + +$ ostree admin status + + gnome-ostree 67e382b11d213a402a5313e61cbc69dfd5ab93cb07.1 + origin refspec: gnome-ostree/buildmaster/x86_64-runtime + * gnome-ostree 67e382b11d213a402a5313e61cbc69dfd5ab93cb07.0 + origin refspec: gnome-ostree/buildmaster/x86_64-runtime + + + + diff --git a/man/ostree-admin-init-fs.xml b/man/ostree-admin-init-fs.xml new file mode 100644 index 0000000..3a93e51 --- /dev/null +++ b/man/ostree-admin-init-fs.xml @@ -0,0 +1,75 @@ + + + + + + + + + ostree admin init-fs + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin init-fs + 1 + + + + ostree-admin-init-fs + Initialize a new root filesystem + + + + + ostree admin init-fs OPTIONS PATH + + + + + Description + + + Initialize an empty physical root filesystem in the designated PATH, with normal toplevels and correct permissions for each directory. Primarily useful for operating system installers. + + + + + Example + $ mkdir /example + $ ostree admin init-fs /example + $ ls /example + + boot   dev   home   ostree   proc   root   run   sys   tmp + + + diff --git a/man/ostree-admin-instutil.xml b/man/ostree-admin-instutil.xml new file mode 100644 index 0000000..323c6e6 --- /dev/null +++ b/man/ostree-admin-instutil.xml @@ -0,0 +1,92 @@ + + + + + + + + + ostree admin instutil + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin instutil + 1 + + + + ostree-admin-instutil + Utility functions intended primarily for operating system installation programs + + + + + ostree admin instutil SUBCOMMAND ARGS + + + + + Description + + + Use the subcommands to toggle admin installation utilities for selinux policies and kernel arguments. + + + + + + Subcommands + + + + selinux-ensure-labeled SUBPATH PREFIX + + + Ensure all files and directories are labeled according to SELinux policy of the first deployment. + + + + + +set-kargs --merge --import-proc-cmdline --append="NAME=VALUE" --replace="NAME=VALUE" MORE_APPEND_ARGS + + + Replace the kernel arguments of the default deployment. The new arguments are based + on an empty list (the default), the current options (--merge), or the arguments + of the loaded kernel (--import-proc-cmdline), and new options either are added to the + end (--append="NAME=VALUE") or replace existing arguments of the same name (--replace="NAME=VALUE"). + + + + + diff --git a/man/ostree-admin-os-init.xml b/man/ostree-admin-os-init.xml new file mode 100644 index 0000000..51cb24e --- /dev/null +++ b/man/ostree-admin-os-init.xml @@ -0,0 +1,77 @@ + + + + + + + + + ostree admin os-init + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin os-init + 1 + + + + ostree-admin-os-init + Initialize empty state for a given operating system + + + + + ostree admin os-init STATEROOT + + + + + Description + + + Initializes an new stateroot (AKA "osname") for an operating system. + Ensures that the core subdirectories of /var (/tmp, /lib, /run, and + /lock) exist and initialize the given STATEROOT as OSTree stateroot. + Each deployment location is comprised of a single shared + var and a set of deployments (chroots). + + + + + Example + $ ostree admin os-init exampleos + + ostree/deploy/exampleos initialized as OSTree root + + + diff --git a/man/ostree-admin-pin.xml b/man/ostree-admin-pin.xml new file mode 100644 index 0000000..db0787a --- /dev/null +++ b/man/ostree-admin-pin.xml @@ -0,0 +1,82 @@ + + + + + + + + + ostree admin pin + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin pin + 1 + + + + ostree-admin-pin + Explicitly retain deployment at a given index + + + + + ostree admin pin INDEX + + + + + Description + + + Ensures the deployment at INDEX, will not be garbage + collected by default. This is termed "pinning". If the + -u option is provided, undoes a pinning operation. + + + + + Options + + + + , + + + Undoes a pinning operation. + + + + + + diff --git a/man/ostree-admin-set-origin.xml b/man/ostree-admin-set-origin.xml new file mode 100644 index 0000000..ffa5cd2 --- /dev/null +++ b/man/ostree-admin-set-origin.xml @@ -0,0 +1,98 @@ + + + + + + + + + ostree admin set-origin + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin set-origin + 1 + + + + ostree-admin-set-origin + Change the "origin" (location for upgrades) + + + + + ostree admin set-origin REMOTENAME URL BRANCH + + + + + Description + + + Add a new remote named + REMOTENAME (if it does not + already exist). Then change the origin file for the + current deployment. This is the ref that will be + "tracked" and upgraded with ostree admin + upgrade. + + + + + Options + + + + =KEY=VALUE + + + Set an option for the remote. + + + + + =INDEX + + Change the origin of the deployment + numbered INDEX (starting + from 0). + + + + + + Example + + $ ostree admin set-origin exampleos http://os.example.com/repo exampleos/10.0/master/router + + diff --git a/man/ostree-admin-status.xml b/man/ostree-admin-status.xml new file mode 100644 index 0000000..096c0da --- /dev/null +++ b/man/ostree-admin-status.xml @@ -0,0 +1,76 @@ + + + + + + + + + ostree admin status + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin status + 1 + + + + ostree-admin-status + List deployments + + + + + ostree admin status + + + + + Description + + + Lists the deployments available to be booted into. Includes osname, the checksum followed by the deploy serial, and the refspec. An asterisk indicates the current booted deployment. + + + + + Example + $ ostree admin status + + * gnome-ostree 67e382b11d213a402a5313e61cbc69dfd5ab93cb07.0 + origin refspec: gnome-ostree/buildmaster/x86_64-runtime + gnome-ostree ce19c41036cc45e49b0cecf6b157523c2105c4de1c.0 + origin refspec: gnome-ostree/buildmaster/x86_64-runtime + + + diff --git a/man/ostree-admin-switch.xml b/man/ostree-admin-switch.xml new file mode 100644 index 0000000..0fba9eb --- /dev/null +++ b/man/ostree-admin-switch.xml @@ -0,0 +1,85 @@ + + + + + + + + + ostree admin switch + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin switch + 1 + + + + ostree-admin-switch + Construct new tree from current origin and deploy it, if it changed + + + + + ostree admin switch REF + + + + + Description + + + Choose a different REF forom the current remote to track. This is the ref that will be "tracked" and upgraded with ostree admin upgrade. Like an upgrade, the operating system state will be preserved. + + + + + Options + + + + ="STATEROOT" + + + Use a different operating system root than the current one. + + + + + + + Example + + $ ostree admin switch fedostree/20/workstation/gnome/core + + diff --git a/man/ostree-admin-undeploy.xml b/man/ostree-admin-undeploy.xml new file mode 100644 index 0000000..818f12d --- /dev/null +++ b/man/ostree-admin-undeploy.xml @@ -0,0 +1,87 @@ + + + + + + + + + ostree admin undeploy + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin undeploy + 1 + + + + ostree-admin-undeploy + Delete deployment at a given index + + + + + ostree admin undeploy INDEX + + + + + Description + + + Deletes the deployment at INDEX. INDEX must be in range and not reference the currently booted deployment. + + + + + Example + $ ostree admin status + + * gnome-ostree 67e382b11d213a402a5313e61cbc69dfd5ab93cb07.0 + origin refspec: gnome-ostree/buildmaster/x86_64-runtime + gnome-ostree ce19c41036cc45e49b0cecf6b157523c2105c4de1c.0 + origin refspec: gnome-ostree/buildmaster/x86_64-runtime + +$ ostree admin undeploy 1 + + Transaction complete; bootconfig swap: no deployment count change: -1) + Freed objects: 326.5 kB + Deleted deployment ce19c41036cc45e49b0cecf6b157523c2105c4de1c.0 + +$ ostree admin status + + * gnome-ostree 67e382b11d213a402a5313e61cbc69dfd5ab93cb07.0 + origin refspec: gnome-ostree/buildmaster/x86_64-runtime + + + diff --git a/man/ostree-admin-unlock.xml b/man/ostree-admin-unlock.xml new file mode 100644 index 0000000..e07f72a --- /dev/null +++ b/man/ostree-admin-unlock.xml @@ -0,0 +1,90 @@ + + + + + + + + + ostree admin unlock + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin unlock + 1 + + + + ostree-admin-unlock + Prepare the current deployment for hotfix or development + + + + + ostree admin unlock OPTIONS + + + + + Description + + + Remove the read-only bind mount on /usr + and replace it with a writable overlay filesystem. This + default invocation of "unlock" is intended for + development/testing purposes. All changes in the overlay + are lost on reboot. However, this command also supports + "hotfixes", see below. + + + + + Options + + + + + + If this option is provided, the + current deployment will be cloned as a rollback + target. This option is intended for things like + emergency security updates to userspace components + such as sshd. The semantics here + differ from the default "development" unlock mode + in that reboots will retain any changes (which is what + you likely want for security hotfixes). + + + + + diff --git a/man/ostree-admin-upgrade.xml b/man/ostree-admin-upgrade.xml new file mode 100644 index 0000000..8d0cb43 --- /dev/null +++ b/man/ostree-admin-upgrade.xml @@ -0,0 +1,133 @@ + + + + + + + + + ostree admin upgrade + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin upgrade + 1 + + + + ostree-admin-upgrade + Construct new tree from current origin and deploy it, if it changed + + + + + ostree admin upgrade OPTIONS + + + + + Description + + + Downloads the latest version of the current ref from the build + server and deploys it, if it changed. Reboot the machine for the + changes to take effect. These phases can be split via + and . + + + + + Options + + + + ="STATEROOT" + + + Use a different operating system root than the current one. + + + + + + + Only perform a pull into the repository; do not + create a deployment. This option can hence safely be used in a + background scheduled job with the assurance of not changing + system state. + + + + + + Create a new deployment from the latest commit + in the tracked origin refspec. This option is intended to be used + by a scheduled system that detected changes via , + and is ready to deploy them. + + + + , + + + Reboot after a successful upgrade. + + + + + + + + Permit deployment of chronologically older trees. + + + + + ="CHECKSUM" + + + Deploy CHECKSUM instead of the latest tree. + + + + + + + + Example + $ ostree admin upgrade + + No update available. + + + diff --git a/man/ostree-admin.xml b/man/ostree-admin.xml new file mode 100644 index 0000000..5dc8146 --- /dev/null +++ b/man/ostree-admin.xml @@ -0,0 +1,114 @@ + + + + + + + + + ostree admin + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree admin + 1 + + + + ostree-admin + Use one of the ostree admin commands + + + + + ostree admin SUBCOMMAND + + + + + Description + + + Use ostree admin subcommands. + + + + + Subcommands + + + cleanup + config-diff + deploy + init-fs + instutil + os-init + pin + set-origin + status + switch + undeploy + unlock + upgrade + + + + View manpages for each admin subcommand using, for example: + + + $ man ostree-admin cleanup + + + + Options + + + , + Usage help + + + + + ="PATH" + Creates a new OSTree sysroot at PATH + + + + + + Prints the full path to the deployment directory for the currently active deployment in the specified sysroot to standard out. This is incompatible with specifying a subcommand. + + + + + diff --git a/man/ostree-cat.xml b/man/ostree-cat.xml new file mode 100644 index 0000000..cf1cdb1 --- /dev/null +++ b/man/ostree-cat.xml @@ -0,0 +1,74 @@ + + + + + + + + + ostree cat + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree cat + 1 + + + + ostree-cat + Display or concatenate contents of files + + + + + ostree cat COMMIT PATH + + + + + Description + + + This command functions much like the typical Unix "cat" command, in that it displays the contents of a file, or concatenates them given two or more files. However, this command requires the user to specify a commit - a checksum or refspec corresponding to a given build. If you use a refspec, OSTree will refer to the most recent commit, unless you specify a parent build using the carat (^) at the end of the refspec. It will then operate the command in that given commit. + + + + + + Example + $ ostree cat my-branch helloworld.txt + + Hello, world! + + + diff --git a/man/ostree-checkout.xml b/man/ostree-checkout.xml new file mode 100644 index 0000000..3956e34 --- /dev/null +++ b/man/ostree-checkout.xml @@ -0,0 +1,217 @@ + + + + + + + + + ostree checkout + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree checkout + 1 + + + + ostree-checkout + Check out a commit into a filesystem + + + + + ostree checkout OPTIONS COMMIT DESTINATION + + + + + Description + + + Checks out the given commit into the filesystem under directory DESTINATION. If DESTINATION is not specified, the COMMIT will become the destination checkout target. If COMMIT destination already exists, command will error unless option is selected. + + + + + Options + + + + , + + + Do not change file ownership or initialize extended attributes. + + + + + ="PATH" + + + Checkout sub-directory PATH. + + + + + + + + Keep existing directories and unchanged files, overwrite existing files. + + + + + + + + Keep existing directories and files. + + + + + + + Like --union, but error out + if a file would be replaced with a different file. Add new files + and directories, ignore identical files, and keep existing + directories. Requires -H. + + + + + + + Process whiteout files (Docker style). + + + + + + + + Do nothing if specified path does not exist. + + + + + + + + Process many checkouts from standard input. + + + + + ="FILE" + + + Process many checkouts from input file. + + + + + ="POLICY" + + + POLICY is a boolean which specifies whether fsync should be + used or not. Default to true. + + + + + , + + + + Do not fall back to full copies if hardlinking fails. + + + + + , + + + + Do not hardlink zero-sized files. + + + + + , + + + Never hardlink (but may reflink if available). + + + + + , + + + + Suppress mode bits outside of 0775 for directories (suid, + world writable, etc.). + + + + + ="FILE" + + + Skip checking out the absolute file paths listed in FILE, + one per line. + + + + + + + + Set SELinux labels based on policy in root filesystem PATH + (may be /). This implies --force-copy. + + + + + + + + Example + $ ostree checkout my-branch + $ ls + + file1    file2    my-branch + + + diff --git a/man/ostree-checksum.xml b/man/ostree-checksum.xml new file mode 100644 index 0000000..ae7aa96 --- /dev/null +++ b/man/ostree-checksum.xml @@ -0,0 +1,86 @@ + + + + + + + + + ostree checksum + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree checksum + 1 + + + + ostree-checksum + Checksum a file or directory + + + + + ostree checksum PATH + + + + + Description + + + Generates a checksum for a given file or directory. + + + + + Options + + + + + + Ignore extended attributes when checksumming. + + + + + + + Example + $ ostree checksum file1 + + 67e382b11d213a402a5313e61cbc69dfd5ab93cb07fbb8b71c2e84f79fa5d7dc + + + diff --git a/man/ostree-commit.xml b/man/ostree-commit.xml new file mode 100644 index 0000000..b0c5b33 --- /dev/null +++ b/man/ostree-commit.xml @@ -0,0 +1,306 @@ + + + + + + + + + ostree commit + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree commit + 1 + + + + ostree-commit + Commit a new revision + + + + + ostree commit OPTIONS --branch=BRANCH PATH + + + + + Description + + + This allows you to commit changes to a branch. The specification of the branch is required. The command will print the checksum of a successful commit. + + + + + Options + + + , ="SUBJECT" + + + One line subject. (optional) + + + + + , ="BODY" + + + Full description. (optional) + + + + + , + + + Open a text editor for the commit description. It will use OSTREE_EDITOR, VISUAL, EDITOR, or vi, in descending order of preference. The commit will be aborted if the message is left empty. + + + + + , ="BRANCH" + + + Branch. Required, unless --orphan is given. + + + + + ="dir=PATH" or "tar=TARFILE" or "ref=COMMIT" + + + Overlay the given argument as a tree. When committing an archive, the TARFILE can be specified as - to read the archive from standard input. + + + + + ="REV" + + + Start from the content in a commit. This differs from --tree=ref=REV in that no commit modifiers are applied. This is usually what you want when + creating a derived commit. This is also used for --selinux-policy-from-base. + + + + + ="KEY=VALUE" + + + Add a key/value pair to metadata. + + + + + ="KEY=VALUE" + + + Add a key/value pair to detached metadata. + + + + + ="UID" + + + Set file ownership user id. + + + + + ="GID" + + + Set file ownership group id. + + + + + + + Do not import extended attributes. + + + + + + + + Optimize for commits of trees composed of hardlinks into the repository. + + + + + + + + When loading tar archives, automatically create parent directories as needed. + + + + + + + + If the contents are unchanged from previous commit, do nothing. + + + + + + + + When committing from a local directory (i.e. not an archive or --tree=ref), + assume ownership of the content. This may simply involve deleting it, + but if possible, the content may simply be rename()ed + into the repository rather than creating a new copy. + + + + + ="PATH" + + + File containing list of modifications to make permissions (file mode, followed by space, followed by file path). + + + + + ="PATH" + + + File containing list of file paths to skip (one path per line). + + + + + + + + Output more information in a KEY: VALUE format. + + + + + + + + Generate size information along with commit metadata. + + + + + ="KEY-ID" + + + GPG Key ID with which to sign the commit (if have GPGME - GNU Privacy Guard Made Easy). + + + + + ="HOMEDIR" + + + GPG home directory to use when looking for keyrings (if have GPGME - GNU Privacy Guard Made Easy). + + + + + ="TIMESTAMP" + + + Override the timestamp of the commit to TIMESTAMP. + + + + + + + + Create a commit without writing to a ref (branch) + + + + + ="POLICY" + + + POLICY is a boolean which specifies whether fsync should be used or not. Default to true. + + + + + + + Use particular signature engine. Currently + available ed25519 and dummy + signature types. + + The default is ed25519. + + + + + ="KEY-ID" + + There KEY-ID is: + + + + + base64-encoded secret key for commit signing. + + + + + + + ASCII-string used as secret key. + + + + + + + + + + Example + $ ostree commit --branch=my-branch --subject="Initial commit" + + 67e382b11d213a402a5313e61cbc69dfd5ab93cb07fbb8b71c2e84f79fa5d7dc + + + diff --git a/man/ostree-config.xml b/man/ostree-config.xml new file mode 100644 index 0000000..e5391bb --- /dev/null +++ b/man/ostree-config.xml @@ -0,0 +1,103 @@ + + + + + + + + + ostree config + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree config + 1 + + + + ostree-config + Change configuration settings + + + + + ostree config get GROUPNAME.KEYNAME + + + ostree config get --group=GROUPNAME KEYNAME + + + ostree config set GROUPNAME.KEYNAME VALUE + + + ostree config set --group=GROUPNAME KEYNAME VALUE + + + ostree config unset GROUPNAME.KEYNAME + + + ostree config unset --group=GROUPNAME KEYNAME + + + + + Description + + + + ostree config get displays the value of + KEYNAME in the group GROUPNAME + + + ostree config set sets the value of + KEYNAME in the group GROUPNAME + to VALUE. + + + ostree config unset removes the key + KEYNAME from the group GROUPNAME + so that OSTree uses the default value for it. It is not an + error for the specified GROUPNAME or + KEYNAME not to exist. + + + + + + Example + $ ostree config get core.mode + bare + $ ostree config set --group='remote "myremote"' url http://example.com/repo + $ ostree config unset core.lock-timeout-secs + + diff --git a/man/ostree-create-usb.xml b/man/ostree-create-usb.xml new file mode 100644 index 0000000..90b2fc5 --- /dev/null +++ b/man/ostree-create-usb.xml @@ -0,0 +1,131 @@ + + + + + + + + + ostree create-usb + OSTree + + + + Developer + Matthew + Leeds + matthew.leeds@endlessm.com + + + + + + ostree create-usb + 1 + + + + ostree-create-usb + Put the given refs on an external drive for P2P distribution. + + + + + ostree create-usb OPTIONS MOUNT-PATH COLLECTION-ID REF COLLECTION-ID REF + + + + + Description + + + This command creates a repository in MOUNT-PATH and pulls the given + REF(s) into it so they can be found and pulled from (perhaps by another computer that's offline). + See + ostree-find-remotes1 + for more information on P2P distribution. + + + In order for ostree to pull refs from a mounted filesystem (such as + a USB drive) the repo must be in a standard location. Specifically, + subdirectories of .ostree/repos.d are checked, + then .ostree/repo, ostree/repo, + and var/lib/flatpak/repo are checked. By default + ostree create-usb uses .ostree/repo, + but if you specify another location using + a symbolic link will be created for you in .ostree/repos.d. + + + This command will regenerate the summary file + in the destination repo so that it stays accurate, so you shouldn't + try to use summary signatures in the destination repo. This + shouldn't be a concern because clients that support pulling from + USB mounts use signed per-repo and per-commit metadata instead of + summary signatures. + + + + + Options + + + + + + + Do not invoke fsync(). + + + + + + =DEST + + + Create the repository in DEST under MOUNT-PATH, rather than + the default location. + + + + + =COMMIT + + + Pull COMMIT instead of whatever REF points to. This can only + be used if a single ref is specified. + + + + + + + + Example + ostree --repo=/var/lib/flatpak/repo create-usb /run/media/mwleeds/f6d04c7a-60f6-4ba3-bb96-0f40498675be com.exampleos.Apps app/org.kde.Khangman/x86_64/stable com.exampleos.Apps ostree-metadata com.exampleos.Apps appstream/x86_64 + + +5 metadata, 213 content objects imported; 1 KiB transferred in 1 seconds Copied 3/3 refs successfully from ‘/var/lib/flatpak/repo’ to ‘.ostree/repo’ repository in ‘/run/media/mwleeds/f6d04c7a-60f6-4ba3-bb96-0f40498675be’. + + + + diff --git a/man/ostree-diff.xml b/man/ostree-diff.xml new file mode 100644 index 0000000..0b7ac89 --- /dev/null +++ b/man/ostree-diff.xml @@ -0,0 +1,113 @@ + + + + + + + + + ostree diff + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree diff + 1 + + + + ostree-diff + Compare a directory against a revision + + + + + ostree diff OPTIONS REV_OR_DIR REV_OR_DIR + + + + + Description + + + Compare a directory or revision against another directory or revision. If REV_OR_DIR starts with `/` or `./`, it is interpreted as a directory, otherwise a revision. Shows files and directories modified, added, and deleted. If there is a file in the second REV_OR_DIR not in the first, it will show with an "A" for "added". If a file in the first REV_OR_DIR is not in the second, it shows "D" for "deleted". "M" for "modified" will also show. + + + + + Options + + + + + + Print various statistics. + + + + + + + Print filesystem diff. + + + + + + + Use file ownership user id for local files. + + + + + + + Use file ownership group id for local files. + + + + + + + Example + $ ostree diff my-branch^ my-branch + + A /testdirectory + M /helloworld.txt + +$ ostree diff my-branch my-branch^ + + D /testdirectory + M /helloworld.txt + + + diff --git a/man/ostree-export.xml b/man/ostree-export.xml new file mode 100644 index 0000000..019fd65 --- /dev/null +++ b/man/ostree-export.xml @@ -0,0 +1,72 @@ + + + + + + + + + ostree export + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree export + 1 + + + + ostree-export + Generate a tar archive from an OSTree commit + + + + + ostree export OPTIONS BRANCH + + + + + Description + + + This command generates a GNU tar formatted archive from an + OSTree commit. This is useful for cases like backups, + converting OSTree commits into Docker images, and the like. + + + + + Example + $ ostree export exampleos/x86_64/standard | gzip > exampleos-standard.tar.gz + + diff --git a/man/ostree-find-remotes.xml b/man/ostree-find-remotes.xml new file mode 100644 index 0000000..89e278d --- /dev/null +++ b/man/ostree-find-remotes.xml @@ -0,0 +1,147 @@ + + + + + + + + + ostree find-remotes + OSTree + + + + Developer + Matthew + Leeds + matthew.leeds@endlessm.com + + + + + + ostree find-remotes + 1 + + + + ostree-find-remotes + Find remotes to serve the given refs + + + + + ostree find-remotes OPTIONS COLLECTION-ID REF COLLECTION-ID REF + + + + + Description + + + OSTree has the ability do pulls not just from configured remote + servers but also from peer computers on the LAN and from mounted + filesystems such as USB drives. This functionality requires the use + of collection IDs and GPG verification. + + + The find-remotes command searches for remotes + which claim to provide one or more of the given COLLECTION-ID REF + pairs and prints information about them, with remotes sorted by + latency (Mounts > LAN > Internet). By default, OSTree searches for + remotes in configuration files, on mounted filesystems (in a + well-known location), and on the LAN using Avahi. Searching for LAN + remotes requires OSTree to have been compiled with Avahi support, + and it requires an Avahi daemon to be running. You can override the + default set of finders (sources for remotes) using the + option documented below. + + + The create-usb command is the recommended way to + put refs on a USB such that find-remotes will + discover them. See + ostree-create-usb1. + + + + + Options + + + + + + + Do not invoke fsync(). + + + + + + =FINDERS + + + Use the specified comma separated list of finders rather than + the default set. Possible values: config, + lan, and mount (or any + combination thereof). + + + + + + + + Pull the most recent commit found for each ref. + + + + + + + + Do a mirror pull (see the documentation for + ostree pull --mirror). This option can + only be used in combination with . + + + + + + + + Example + $ ostree find-remotes --finders=mount,lan com.exampleos.Os exampleos/x86_64/standard + +Result 0: http://10.0.64.202:43381/0 + - Finder: OstreeRepoFinderAvahi + - Keyring: exampleos.trustedkeys.gpg + - Priority: 60 + - Summary last modified: 2018-01-12T19:00:28Z + - Refs: + - (com.exampleos.Os, exampleos/x86_64/standard) = c91acd964b3fda561b87bfb7f7c80e36220d76b567f0ce90c0e60742ef33c360 + +1/1 refs were found. + + + diff --git a/man/ostree-fsck.xml b/man/ostree-fsck.xml new file mode 100644 index 0000000..4e292db --- /dev/null +++ b/man/ostree-fsck.xml @@ -0,0 +1,125 @@ + + + + + + + + + ostree fsck + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree fsck + 1 + + + + ostree-fsck + Check the repository for consistency + + + + + ostree fsckOPTIONS + + + + + Description + + + Checks the repository to verify the content integrity of commit objects. Looks for missing and corrupted objects and metadata, and validates directory structure and metadata. + + + + + Options + + + + , + + Only print error messages. + + + + + + + Remove corrupted objects. + + + + + + + Add tombstone commit for referenced but missing commits. + + + + + + + Verify that the commits pointed to by each ref have that + ref in the binding set. You should usually add this + option; it only defaults to off for backwards compatibility. + + + + + + + Verify that all the refs listed in a commit’s ref-bindings + point to that commit. This cannot be used in repositories + where the target of refs is changed over time as new commits + are added, but can be used in repositories which are + regenerated from scratch for each commit. + Implies --verify-bindings as well. + + + + + + + + Example + $ ostree fsck + + Enumerating objects... + Verifying content integrity of of 2 commit objects + 0/2572 objects + 2571/2572 objects + + + diff --git a/man/ostree-gpg-sign.xml b/man/ostree-gpg-sign.xml new file mode 100644 index 0000000..a6120f0 --- /dev/null +++ b/man/ostree-gpg-sign.xml @@ -0,0 +1,90 @@ + + + + + + + + + ostree gpg-sign + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree gpg-sign + 1 + + + + ostree-gpg-sign + Sign a commit + + + + + ostree gpg-sign OPTIONS COMMIT KEY-ID + + + + + Description + + + Add a new signature to a commit for each specified GPG key. + + Note that currently, this will append a new signature even if + the commit is already signed with a given key. + + + + + Options + + + + + + + Delete signatures having any of the GPG KEY-IDs. + + + + + ="HOMEDIR" + + + GPG Homedir to use when looking for keyrings. + + + + + diff --git a/man/ostree-init.xml b/man/ostree-init.xml new file mode 100644 index 0000000..b272632 --- /dev/null +++ b/man/ostree-init.xml @@ -0,0 +1,122 @@ + + + + + + + + + ostree init + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree init + 1 + + + + ostree-init + Initialize a new empty repository + + + + + ostree init OPTIONS + + + + + Description + + + Creates a new empty repository. + + + + + Options + + + + ="MODE" + + Initialize repository in given mode + (bare, bare-user, + bare-user-only, archive). + The default is bare. Note that for + archive the repository configuration file + will actually have archive-z2, as that's + the historical name. + + See the manual for differences between these modes. + Briefly, bare mode stores files as they + are, so they can be directly hardlinked, + bare-user uses extended attributes to + store ownership and xattr information, allowing non-root + operations, bare-user-only does not store + ownership information, and archive stores + files compressed, to be served over the network. + + + + + =COLLECTION-ID + + Set the collection ID of the repository. Remotes in clones + of this repository must configure the same value in order to + pull refs which originated in this repository over peer to + peer. + + This collection ID must be persistent and globally + unique. It is formatted as a reverse DNS name (like a D-Bus + interface). It must be set to a reverse DNS domain under your + control. + + This option may be omitted (the default) to leave + peer to peer distribution unsupported for the repository. A + collection ID may be added to an existing repository in + future to enable peer to peer distribution from that point + onwards. + + If the collection ID is changed for the repository + in future, peer to peer distribution of refs from the + repository will break for all peers who do not update their + remote configuration to the new collection ID. + + + + + + + + diff --git a/man/ostree-log.xml b/man/ostree-log.xml new file mode 100644 index 0000000..0b7d348 --- /dev/null +++ b/man/ostree-log.xml @@ -0,0 +1,93 @@ + + + + + + + + + ostree log + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree log + 1 + + + + ostree-log + Show log starting at a commit or ref + + + + + ostree log OPTIONS REF + + + + + Description + + + Shows a log of commits to a given ref or branch. Includes commit checksum, timestamp, and commit message. + + + + + Options + + + + + + Show raw variant data. + + + + + + + Example + $ ostree log my-branch + + commit 67e382b11d213a402a5313e61cbc69dfd5ab93cb07fbb8b71c2e84f79fa5d7dc + Date: 2014-06-12 13:42:54 +0000 + This is the second commit + + commit ce19c41036cc45e49b0cecf6b157523c2105c4de1ce30101def1f759daafcc3e + Date: 2014-06-12 11:20:08 +0000 + Initial commit + + + + diff --git a/man/ostree-ls.xml b/man/ostree-ls.xml new file mode 100644 index 0000000..a0a9bb5 --- /dev/null +++ b/man/ostree-ls.xml @@ -0,0 +1,119 @@ + + + + + + + + + ostree ls + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree ls + 1 + + + + ostree-ls + List file paths + + + + + ostree ls OPTIONS COMMIT PATHS + + + + + Description + + + Prints a list of file paths within the given commit, and within the given path(s) if specified. The first letter of the file line output specifies the type: "-" for regular file, "d" for directory, "l" for symbolic link. See EXAMPLE section for more detail on the specific output. + + + + + Options + + + + , + + Do not recurse into directory arguments. + + + + + , + + Print directories recursively. + + + + + , + + Print checksum. + + + + + , + + Print extended attributes. + + + + + + + Print only filenames, NUL separated. + + + + + + + + Example + $ ostree ls my-branch + + d00644 0 0 0 / + -00644 0 0 2 /helloworld.txt + d00755 0 0 0 /testdirectory + + +Here, the first column is the file-type symbol (as explained in the DESCRIPTION section) followed by the S_IFMT file type. The next two columns (here: 0 0) are respectively the user ID and group ID for the file. After the break, the next number represents that file's standard size. The final column is the file path. + + diff --git a/man/ostree-prune.xml b/man/ostree-prune.xml new file mode 100644 index 0000000..f1b517f --- /dev/null +++ b/man/ostree-prune.xml @@ -0,0 +1,137 @@ + + + + + + + + + ostree prune + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree prune + 1 + + + + ostree-prune + Search for unreachable objects + + + + + ostree prune OPTIONS + + + + + Description + + + This searches for unreachable objects in the current repository. If unreachable objects are found, the command delete them to free space. If the option is invoked, the command will just print unreachable objects and recommend deleting them. + + + + + Options + + + + + + + Only display unreachable objects; don't delete. + + + + + + + + Only compute reachability via refs. + + + + + =COMMIT + + + Specify a COMMIT to delete. + + + + + =DATE + + + All commits older than DATE will be + pruned. The format of DATE is the same as that + accepted by GNU date utility - for more information + see info date. + + + + + =DEPTH + + + Only traverse DEPTH (integer) parents for each commit (default: -1=infinite). + + + + + =DEPTH + + + This option may currently only be used in combination with + . Previous versions of ostree silently accepted + the option without that, and ignored it. However, there are desired use + cases for pruning just static deltas (while retaining the commits), and it's + likely at some point this option will be supported for use cases outside of just + . + + + + + + + + Example + $ ostree prune + + Total objects: 25627 + No unreachable objects + + + diff --git a/man/ostree-pull-local.xml b/man/ostree-pull-local.xml new file mode 100644 index 0000000..2bfb2b0 --- /dev/null +++ b/man/ostree-pull-local.xml @@ -0,0 +1,106 @@ + + + + + + + + + ostree pull-local + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree pull-local + 1 + + + + ostree-pull-local + Copy data from a source repository + + + + + ostree pull-local OPTIONS SOURCE_REPO REFS + + + + + Description + + + Copies data from a given repository; optimized for copies only between repositories on the same system. + + + + + Options + + + + ="REMOTE" + + + Add REMOTE to refspec. + + + + + + + + Do no invoke fsync(). + + + + + + + + Do not trust source, verify checksums and don't hardlink into source. + + + + + + + + Example + $ ostree pull-local /ostree/repo + + Enumerating objects... + pull: 25709/25709 scanned, 0 objects copied + Writing 5 refs + + + diff --git a/man/ostree-pull.xml b/man/ostree-pull.xml new file mode 100644 index 0000000..0606f69 --- /dev/null +++ b/man/ostree-pull.xml @@ -0,0 +1,191 @@ + + + + + + + + + ostree pull + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree pull + 1 + + + + ostree-pull + Download data from a remote repository + + + + + ostree pull REMOTE BRANCH + + + + + Options + + + + + + + Fetch only the commit metadata. + + + + + + + + Do no invoke fsync(). + + + + + + + + Like git's clone --reference. Reuse the provided + OSTree repo as a local object cache when doing HTTP fetches. + May be specified multiple times. + + + + + + + + Do not trust local sources, verify checksums and don't hardlink into source. + + + + + + + + Do not use static deltas. + + + + + + + + Write refs suitable for a mirror, i.e. refs are stored in the + heads/ directory rather than the + remotes/ directory. This makes the target repo + suitable to be exported for other clients to pull from as an ostree + remote. If no specific refs are specified, all refs will be fetched (the + remote must have a summary file present). + + + + + =SUBPATH + + + Only pull the provided subpath. + + + + + =DEPTH + + + Traverse DEPTH parents (-1=infinite) (default: 0). + + + + + =N + + + Specifies how many times each download should be retried upon error (default: 5) + + + + + + + Description + + + Without --mirror, this command will create new refs + under remotes/REMOTE/ directory + for each pulled branch unless they are already created. Such + refs can be then referenced by REMOTE:BRANCH in + ostree subcommands (e.g. ostree log origin:exampleos/x86_64/standard). + + + + This command can retrieve just a specific commit, or go all + the way to performing a full mirror of the remote + repository. If no BRANCH is specified, + all configured branches are retrieved. + + + + A special syntax in the @ character allows + specifying a specific commit to retrieve from a branch. The + use cases for this are somewhat similar to pulling a specific + git tag; one could e.g. script a system upgrade to a known-good + version, rather than the latest from the content provider. + + + + + + Example + + $ ostree --repo=repo pull --depth=-1 --mirror remote_name + + Perform a complete mirror of the remote. (This is + likely most useful if your repository is also + archive mode) + + $ ostree --repo=repo pull remote_name exampleos/x86_64/standard + + Fetch the most recent commit to exampleos/x86_64/standard. + + $ ostree --repo=repo pull remote_name exampleos/x86_64/standard@98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4 + + Download the specific commit starting with + 98ea6e as if it was the latest commit for + exampleos/x86_64/standard. + + + diff --git a/man/ostree-refs.xml b/man/ostree-refs.xml new file mode 100644 index 0000000..0ba6b1d --- /dev/null +++ b/man/ostree-refs.xml @@ -0,0 +1,150 @@ + + + + + + + + + ostree refs + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree refs + 1 + + + + ostree-refs + List refs + + + + + ostree refs OPTIONS PREFIX + + + ostree refs EXISTING --create=NEWREF + + + + + + Description + + Lists all refs available on the host. If specified, PREFIX assigns the refspec prefix; default + prefix is null, which lists all refs. This command can also be used to create or delete refs. + + + + + Options + + + + + + For historical reasons, refs + without this option will strip the specified prefix + from the output. Normally, one wants to see the full + ref, so providing this option ensures the refs are + printed in full, rather than + truncated. + + + + =NEWREF + + + Create a ref pointing to the commit EXISTING. NEWREF must not already exist, and EXISTING + must be an existing commit. More than one ref can point to the same commit. + + + + + + + + Delete refs which match PREFIX, rather than listing them. If you are trying to reclaim space, + you will then need to ostree prune or ostree admin cleanup. + + + + + , + + + If used with , create an alias. Otherwise just list aliases. + + + + + , + + + Enable interactions with refs using the combination of their + collection IDs and ref names. When listing refs, this changes + the output format to include collection IDs, and enables + listing remote mirrored refs. + + When creating refs, the refspec value passed to the + option is treated as + COLLECTION-ID:REF-NAME and a mirrored ref + is created. (This is an abuse of the refspec syntax.) + + When deleting refs, all refs whose collection ID equals + PREFIX are deleted. + + + + + + + + When creating NEWREF with + , allow an existing ref to be + updated instead of erroring. + + + + + + + Example + $ ostree refs + + my-branch + gnome-ostree/buildmaster/x86_64-runtime + + + diff --git a/man/ostree-remote.xml b/man/ostree-remote.xml new file mode 100644 index 0000000..407f7e3 --- /dev/null +++ b/man/ostree-remote.xml @@ -0,0 +1,241 @@ + + + + + + + + + ostree remote + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree remote + 1 + + + + ostree-remote + Control remote repository configuration + + + + + ostree remote add OPTIONS NAME URL BRANCH + + + ostree remote delete NAME + + + ostree remote show-url NAME + + + ostree remote list OPTIONS NAME + + + ostree remote gpg-import OPTIONS NAME KEY-ID + + + ostree remote refs NAME + + + ostree remote summary OPTIONS NAME + + + ostree remote add-cookie + NAME + DOMAIN + PATH + COOKIE_NAME + VALUE + + + ostree remote delete-cookie + NAME + DOMAIN + PATH + COOKIE_NAME + VALUE + + + ostree remote list-cookies NAME + + + + + Description + + + Changes remote repository configurations. The NAME refers to the name of the remote. + + + The BRANCH arguments to the + add subcommand specifies the configured branches + for the remote. See the branches section in + ostree.repo-config5 + for more information. + + + The gpg-import subcommand can associate GPG keys to a specific remote repository for use when pulling signed commits from that repository (if GPG verification is enabled). + + + The GPG keys to import may be in binary OpenPGP format or ASCII armored. The optional KEY-ID list can restrict which keys are imported from a keyring file or input stream. All keys are imported if this list is omitted. If neither nor options are given, then keys are imported from the user's personal GPG keyring. + + + The various cookie related command allow management of a remote specific cookie jar. + + + + + 'Add' Options + + + + ="KEY=VALUE" + + + Set config option KEY=VALUE for remote. + + + + + + + + Do nothing if the provided remote exists. + + + + + + + + Replace the provided remote if it exists. + + + + + + + + Disable GPG verification. + + + + + =FILE + + + Import one or more GPG keys from a file. + + Equivalent to + ostree remote gpg-import --keyring=FILE. + + + + + =COLLECTION-ID + + + Set the collection ID for the remote to a value provided by + the repository owner, which allows refs from this remote to be + shared peer to peer. + + + + + + + 'List' Options + + + + + + + Show remote URLs in list + + + + + + + 'GPG-Import' Options + + + + =FILE + + + Import one or more keys from a file. + + This option may be repeated to import from multiple files, + but may not be used in combination with + . + + + + + + + Import one or more keys from standard input. + + This option may not be used in combination with + . + + + + + + + 'Summary' Options + + + + + + + Show raw variant data + + + + + + + Example + $ ostree remote show-url local + + http://192.168.122.1/repo + + + diff --git a/man/ostree-reset.xml b/man/ostree-reset.xml new file mode 100644 index 0000000..e52a1ec --- /dev/null +++ b/man/ostree-reset.xml @@ -0,0 +1,87 @@ + + + + + + + + + ostree reset + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree reset + 1 + + + + ostree-reset + Reset a ref to a previous commit + + + + + ostree reset REF REF_TO_RESET_TO + + + + + Description + + + Given a commit, this command will reset the ref to a previous specified commit. + + + + + Example + $ ostree log my-branch + + commit 67e382b11d213a402a5313e61cbc69dfd5ab93cb07 + Date: 2014-06-12 13:42:54 +0000 + This is the second commit + + commit ce19c41036cc45e49b0cecf6b157523c2105c4de1c + Date: 2014-06-12 11:20:08 +0000 + Initial commit + + +$ ostree reset my-branch my-branch^ + $ ostree log my-branch + + commit ce19c41036cc45e49b0cecf6b157523c2105c4de1c + Date: 2014-06-12 11:20:08 +0000 + Initial commit + + + diff --git a/man/ostree-rev-parse.xml b/man/ostree-rev-parse.xml new file mode 100644 index 0000000..66a4e19 --- /dev/null +++ b/man/ostree-rev-parse.xml @@ -0,0 +1,75 @@ + + + + + + + + + ostree rev-parse + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree rev-parse + 1 + + + + ostree-rev-parse + Output the target of a rev + + + + + ostree rev-parse REV PATH + + + + + + + Description + + + Given a REV, outputs the checksum of the latest commit of that revision. + + + + + Example + $ ostree rev-parse my-branch + + ce19c41036cc45e49b0cecf6b157523c2105c4de1ce30101def1f759daafcc3e + + + diff --git a/man/ostree-show.xml b/man/ostree-show.xml new file mode 100644 index 0000000..a28f704 --- /dev/null +++ b/man/ostree-show.xml @@ -0,0 +1,139 @@ + + + + + + + + + ostree show + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree show + 1 + + + + ostree-show + Output a metadata object + + + + + ostree show OPTIONS OBJECT + + + + + Description + + + Given an object, shows the metadata for that object. For a particular revision, it will show the data for the most recent commit to that revision. + + + + + Options + + + + + + + Show the "related" commits. + + + + + ="TYPE" + + + Memory map OBJECT (in this case a filename) to the GVariant type string. + + + + + ="KEY" + + + Print string value of metadata key. + + + + + ="KEY" + + + Print string value of detached metadata key. + + + + + + + + Show the commit size metadata. This in only supported for + commits that contain ostree.sizes + metadata. This can be included when creating commits with + ostree commit --generate-sizes. + + + + + + + + Show raw variant data. + + + + + ="HOMEDIR" + + + GPG home directory to use when looking for keyrings (if have GPGME - GNU Privacy Guard Made Easy). + + + + + + + Example + $ ostree show my-branch + + commit 67e382b11d213a402a5313e61cbc69dfd5ab93cb07 + Date: 2014-06-12 13:42:54 +0000 + + + diff --git a/man/ostree-sign.xml b/man/ostree-sign.xml new file mode 100644 index 0000000..50c0b33 --- /dev/null +++ b/man/ostree-sign.xml @@ -0,0 +1,152 @@ + + + + + + + + + ostree sign + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree sign + 1 + + + + ostree-sign + Sign a commit + + + + + ostree sign OPTIONS COMMIT KEY-ID + + + + + Description + + + Add a new signature to a commit. + + Note that currently, this will append a new signature even if + the commit is already signed with a given key. + + + + There are several "well-known" system places for `ed25519` trusted and revoked public keys -- expected single base64-encoded key per line. + + + Files: + + /etc/ostree/trusted.ed25519 + /etc/ostree/revoked.ed25519 + /usr/share/ostree/trusted.ed25519 + /usr/share/ostree/revoked.ed25519 + + + + Directories containing files with keys: + + /etc/ostree/trusted.ed25519.d + /etc/ostree/revoked.ed25519.d + /usr/share/ostree/trusted.ed25519.d + /usr/share/ostree/rvokeded.ed25519.d + + + + + + Options + + + + + + + + + + base64-encoded secret (for signing) or public key (for verifying). + + + + + + + ASCII-string used as secret key and public key. + + + + + + + + + Verify signatures + + + + + + Use particular signature mechanism. Currently + available ed25519 and dummy + signature types. + + The default is ed25519. + + + + + + Read key(s) from file filename. + + + + Valid for ed25519 signature type. + For ed25519 this file must contain base64-encoded + secret key(s) (for signing) or public key(s) (for verifying) per line. + + + + + + Redefine the system path, where to search files and subdirectories with + well-known and revoked keys. + + + + + diff --git a/man/ostree-static-delta.xml b/man/ostree-static-delta.xml new file mode 100644 index 0000000..dfeef28 --- /dev/null +++ b/man/ostree-static-delta.xml @@ -0,0 +1,127 @@ + + + + + + + + + ostree static-delta + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree static-delta + 1 + + + + ostree-static-delta + Manage static delta files + + + + + ostree static-delta list + + + ostree static-delta show + + + ostree static-delta delete + + + ostree static-delta generate --to=REV OPTIONS + + + ostree static-delta apply-offline PATH + + + + + Description + + + List and manipulate static delta files. + + + + + 'Generate' Options + + + + ="REV" + + + Create delta from revision REV. + + + + + ="REV" + + + Create delta to revision REV. (This option is required.) + The delta is from the parent of REV, unless specified otherwise by + or . + + + + + + + + Create delta from scratch. + + + + + =SIZE + + + Maximum uncompressed size in megabytes. + + + + + + + + + Example + $ ostree static-delta + + (No static deltas) + + + diff --git a/man/ostree-summary.xml b/man/ostree-summary.xml new file mode 100644 index 0000000..8305b4e --- /dev/null +++ b/man/ostree-summary.xml @@ -0,0 +1,192 @@ + + + + + + + + + ostree summary + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree summary + 1 + + + + ostree-summary + Regenerate or view the summary metadata file + + + + + ostree summary --gpg-sign=KEYID --gpg-homedir=HOMEDIR --sign=KEYID --sign-type=ENGINE --update --add-metadata=KEY=VALUE + + + + ostree summary --view--raw + + + + + Description + + + The summary file is an optional higher + level form of repository metadata that describes the + available branches. It needs to be manually regenerated after + a series of commits. Among other things, this allows atomically + updating multiple commits. + + + + + Options + + + + , + + + Update the summary file. This option can be combined + with to add metadata + fields to the summary. + + + If the repository has a collection ID configured, the + ostree-metadata branch for that collection ID + will also be updated with a new commit containing the given metadata, + which will be signed if the summary file is signed. + + + + + + ,=KEY=VALUE + + + Specify an additional metadata field to add to the summary. + It must be in the format + KEY=VALUE + or as two separate arguments. The keys must be namespaced + for your organisation or repository using a dot prefix. The + values must be in GVariant text format. For example, + exampleos.end-of-life "@t 1445385600". + This option can be used multiple times. + + + + + , + + + View the contents of the summary file in a human readable format. + + + + + + + + View the raw bytes of the summary file. + + + + + =KEYID + + + GPG Key ID to sign the summary with. + + + + + =HOMEDIR + + + GPG Homedir to use when looking for keyrings. + + + + + =ENGINE + + Use particular signature engine. Currently + available ed25519 and dummy + signature types. + + The default is ed25519. + + + + + ="KEY-ID" + + There KEY-ID is: + + + + + base64-encoded secret key for commit signing. + + + + + + + ASCII-string used as secret key. + + + + + + + + + + + Examples + $ ostree summary -u + $ ostree summary -u -m key="'value'" + $ ostree summary -v + +* ostree/1/1/0 + Latest Commit (4.2 MB): + 9828ab80f357459b4ab50f0629beab2ae3b67318fc3d161d10a89fae353afa90 + Timestamp (ostree.commit.timestamp): 2017-11-21T01:41:10-08 + +Last-Modified (ostree.summary.last-modified): 2018-01-12T22:06:38-08 + + + diff --git a/man/ostree-trivial-httpd.xml b/man/ostree-trivial-httpd.xml new file mode 100644 index 0000000..d03c12b --- /dev/null +++ b/man/ostree-trivial-httpd.xml @@ -0,0 +1,118 @@ + + + + + + + + + ostree trivial-httpd + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree trivial-httpd + 1 + + + + ostree-trivial-httpd + Simple webserver + + + + + ostree trivial-httpd OPTIONS DIR + + + + + + Description + + + This runs a simple webserver and keeps it running until killed. If DIR is not specified, it defaults to the current directory. + + + + + Options + + + + , + + + Fork into background when ready. + + + + + + + + Automatically exit when directory is deleted. + + + + + ,="PATH" + + + Write port number to PATH (- for standard output). + + + + + , + + + Use the specified TCP port to listen on. + + + + + + + + Force range requests by only serving half of files. + + + + + + + + Example + $ ostree trivial-httpd + + diff --git a/man/ostree.repo-config.xml b/man/ostree.repo-config.xml new file mode 100644 index 0000000..7a01fc0 --- /dev/null +++ b/man/ostree.repo-config.xml @@ -0,0 +1,451 @@ + + + + + + + + + ostree.repo-config + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree.repo-config + 5 + + + + ostree.repo-config + OSTree repository configuration + + + + Description + + + The config file in an OSTree + repository is a "keyfile" in the XDG + Desktop Entry Specification format. It has + several global flags, as well as zero or more remote + entries which describe how to access remote + repositories. + + + + See ostree.repo5 for more information + about OSTree repositories. + + + + + [core] Section Options + + + Repository-global options. The following entries are defined: + + + + + mode + One of bare, bare-user or archive-z2 (note that archive is used everywhere else.) + + + + repo_version + Currently, this must be set to 1. + + + + auto-update-summary + Boolean value controlling whether or not to + automatically update the summary file after any ref is added, + removed, or updated. Other modifications which may render a + summary file stale (like static deltas, or collection IDs) do + not currently trigger an auto-update. + + + + + commit-update-summary + This option is deprecated. Use + auto-update-summary instead, for which this + option is now an alias. + + + + fsync + Boolean value controlling whether or not to + ensure files are on stable storage when performing operations + such as commits, pulls, and checkouts. Defaults to + true. + + If you disable fsync, OSTree will no longer be robust + against kernel crashes or power loss. + + + You might choose to disable this for local development + repositories, under the assumption they can be recreated from + source. Similarly, you could disable for a mirror where you could + re-pull. + + + For the system repository, you might choose to disable fsync + if you have uninterruptable power supplies and a well tested + kernel. + + + + + + per-object-fsync + By default, OSTree will batch fsync() after + writing everything; however, this can cause latency spikes + for other processes which are also invoking fsync(). + Turn on this boolean to reduce potential latency spikes, + at the cost of slowing down OSTree updates. You most + likely want this on by default for "background" OS updates. + + + + + + min-free-space-percent + + + Integer percentage value (0-99) that specifies a minimum percentage + of total space (in blocks) in the underlying filesystem to keep + free. The default value is 3, which is enforced when neither this + option nor min-free-space-size are set. + + + If min-free-space-size is set to a non-zero + value, min-free-space-percent is ignored. Note + that, min-free-space-percent is not enforced on + metadata objects. It is assumed that metadata objects are relatively + small in size compared to content objects and thus kept outside the + scope of this option. + + + + + + min-free-space-size + + + Value (in power-of-2 MB, GB or TB) that specifies a minimum space + in the underlying filesystem to keep free. Examples of acceptable + values: 500MB (524 288 000 bytes), + 1GB (1 073 741 824 bytes), + 1TB (1 099 511 627 776 bytes). + + + If this option is set to a non-zero value, and + min-free-space-percent is also set, this option + takes priority. Note that, min-free-space-size is + not enforced on metadata objects. It is assumed that metadata objects + are relatively small in size compared to content objects and thus kept + outside the scope of this option. + + + + + + add-remotes-config-dir + + + Boolean value controlling whether new remotes will be added + in the remotes configuration directory. Defaults to + true for system ostree repositories. When + this is false, remotes will be added in + the repository's config file. + + + This only applies to repositories that use a remotes + configuration directory such as system ostree repositories, + which use /etc/ostree/remotes.d. + Non-system repositories do not use a remotes configuration + directory unless one is specified when the repository is + opened. + + + + + + payload-link-threshold + An integer value that specifies a minimum file size for creating + a payload link. By default it is disabled. + + + + + collection-id + A reverse DNS domain name under your control, which enables peer + to peer distribution of refs in this repository. See the + --collection-id section in + ostree-init1 + + + + + locking + Boolean value controlling whether or not OSTree does + repository locking internally. This uses file locks and is + hence for multiple process exclusion (e.g. Flatpak and OSTree + writing to the same repository separately). This is enabled by + default since 2018.5. + + + + + lock-timeout-secs + Integer value controlling the number of seconds to + block while attempting to acquire a lock (see above). A value + of -1 means block indefinitely. The default value is 30. + + + + + default-repo-finders + Semicolon separated default list of finders (sources + for refs) to use when pulling. This can be used to disable + pulling from mounted filesystems, peers on the local network, + or the Internet. However note that it only applies when a set + of finders isn't explicitly specified, either by a consumer of + libostree API or on the command line. Possible values: + config, lan, and + mount (or any combination thereof). If unset, this + defaults to config;mount; (since the LAN finder is + costly). + + + + + + + [remote "name"] Section Options + + + Describes a remote repository location. + + + + + url + Must be present; declares URL for accessing metadata and + content for remote. See also contenturl. The + supported schemes are documented below. + + + + contenturl + Declares URL for accessing content (filez, static delta + parts). When specified, url is used just for + metadata: summary, static delta "superblocks". + + + + branches + A list of strings. Represents the default configured + branches to fetch from the remote when no specific branches are + requested during a pull operation. + + + + proxy + A string value, if given should be a URL for a + HTTP proxy to use for access to this repository. + + + + gpg-verify + A boolean value, defaults to true. + Controls whether or not OSTree will require commits to be + signed by a known GPG key. For more information, see the + ostree1 + manual under GPG. + + + + gpg-verify-summary + A boolean value, defaults to false. + Controls whether or not OSTree will check if the summary + is signed by a known GPG key. + For more information, see the ostree1 + manual under GPG. + + + + tls-permissive + A boolean value, defaults to false. By + default, server TLS certificates will be checked against the + system certificate store. If this variable is set, any + certificate will be accepted. + + + + tls-client-cert-path + Path to file for client-side certificate, to present when making requests to this repository. + + + + tls-client-key-path + Path to file containing client-side certificate key, to present when making requests to this repository. + + + + tls-ca-path + Path to file containing trusted anchors instead of the system CA database. + + + + http2 + A boolean value, defaults to true. By + default, libostree will use HTTP2; setting this to false + will disable it. May be useful to work around broken servers. + + + + + unconfigured-state + If set, pulls from this remote will fail with the configured text. This is intended for OS vendors which have a subscription process to access content. + + + + + + + + [sysroot] Section Options + + + Options for the sysroot, which contains the OSTree repository, + deployments, and stateroots. The following entries are defined: + + + + + + bootloader + Configure the bootloader that OSTree uses when + deploying the sysroot. This may take the values + bootloader=none or bootloader=auto. + Default is auto. + + + If none, then OSTree will generate only BLS (Boot + Loader Specification) fragments in sysroot/boot/loader/entries/ + for the deployment. + + + If auto, then in addition to generating BLS + fragments, OSTree will dynamically check for the existence of grub2, + uboot, and syslinux bootloaders. If one of the bootloaders is found, + then OSTree will generate a config for the bootloader found. For + example, grub2-mkconfig is run for the grub2 case. + + + + + + + + + + /etc/ostree/remotes.d + + + In addition to the /ostree/repo/config + file, remotes may also be specified in + /etc/ostree/remotes.d. The remote + configuration file must end in .conf; files + whose name does not end in .conf will be + ignored. + + + + + Repository url/contenturl + + Originally, OSTree had just a url option + for remotes. Since then, the contenturl + option was introduced. Both of these support + file, http, and + https schemes. + + + Additionally, both of these can be prefixed with the string + mirrorlist=, which instructs the client + that the target url is a "mirrorlist" format, which is + a plain text file of newline-separated URLs. Earlier + URLs will be given precedence. + + + Note that currently, the tls-ca-path and + tls-client-cert-path options apply to every HTTP + request, even when contenturl and/or + mirrorlist are in use. This may change in the future to + only apply to metadata (i.e. url, not + contenturl) fetches. + + + + + Per-remote GPG keyrings and verification + + OSTree supports a per-remote GPG keyring, as well as a + gpgkeypath option. For more information see + ostree1. + in the section GPG verification. + + + + + Per-remote HTTP cookies + + Some content providers may want to control access to remote + repositories via HTTP cookies. The ostree remote + add-cookie and ostree remote + delete-cookie commands will update a per-remote + lookaside cookie jar, named + $remotename.cookies.txt. + + + + + See Also + + ostree1, ostree.repo5 + + + diff --git a/man/ostree.repo.xml b/man/ostree.repo.xml new file mode 100644 index 0000000..0553b63 --- /dev/null +++ b/man/ostree.repo.xml @@ -0,0 +1,101 @@ + + + + + + + + + ostree.repo + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree.repo + 5 + + + + ostree.repo + OSTree repository configuration and layout + + + + Description + + + An OSTree repository is structurally similar to a + git repository; it is a content-addressed object + store containing filesystem trees. However, unlike + git, ostree is designed to store operating system + binaries. It records the Unix uid and gid, + permissions, as well as extended attributes. + + + + A repository can be in one of three modes; + bare, which is designed as a hard + link source for operating system checkouts, + bare-user, which is like + bare but works on systems that + run as non-root as well as non-root containers, and + archive-z2, which is designed for + static HTTP servers. + + + + There is a system repository located at + /ostree/repo. If no repository + is specified -- either by a command-line option or the + OSTREE_REPO environment variable -- + the ostree as well as many API + calls will use it by default. + + + + + Components of a repository + + + The only user-editable component is the + config file. For more + information, see ostree.repo-config5. + + + + + See Also + + ostree1, ostree.repo-config1 + + + diff --git a/man/ostree.xml b/man/ostree.xml new file mode 100644 index 0000000..8c08bae --- /dev/null +++ b/man/ostree.xml @@ -0,0 +1,492 @@ + + + + + + + + + ostree + OSTree + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + ostree + 1 + + + + ostree + Manage multiple bootable versioned filesystem trees + + + + + ostree + COMMAND OPTIONS + + + + + Description + + + OSTree is a tool for managing multiple bootable + versioned filesystem trees, or just "tree" for + short. In the OSTree model, operating systems no + longer live in the physical "/" root directory. + Instead, they parallel install to the new toplevel + /ostree directory. Each + installed system gets its own + /ostree/deploy/stateroot + directory. (stateroot is the + newer term for osname). + + + Unlike rpm or + dpkg, OSTree is only aware of + complete filesystem trees. It has no built-in + knowledge of what components went into creating the + filesystem tree. + + + It is possible to use OSTree in several modes; the + most basic form is to replicate pre-built trees from + a build server. Usually, these pre-built trees are + derived from packages. You might also be using + OSTree underneath a higher level tool which computes + filesystem trees locally. + + + It must be emphasized that OSTree only supports + read-only trees. To change to + a different tree (upgrade, downgrade, install + software), a new tree is checked out, and a 3-way + merge of configuration is performed. The currently + running tree is not ever modified; the new tree will + become active on a system reboot. + + + + To see the man page for a command run man ostree COMMAND or man ostree-admin COMMAND + + + + + Options + + The following options are understood: + + + + + + + For most commands, a repository is + required. If unspecified, the current + directory is used if it appears to be an + OSTree repository. If it isn't, either + the OSTREE_REPO + environment variable is used, or the + system repository located at + /sysroot/ostree/repo. + + + + + + + + Produce debug level output. + + + + + + + + Print version information, including the features enabled + at compile time, and exit. + + + + + + + Commands + + System administrators will primarily interact + with OSTree via the subcommand ostree + admin. + + + + ostree-admin-cleanup1 + + +  Delete untagged + deployments and repository objects. + + + + + ostree-admin-config-diff1 + + +  See changes to + /etc as compared + to the current default (from + /usr/etc). + + + + + ostree-admin-deploy1 + + +  Takes a particular + commit or revision, and sets it up for + the next boot. + + + + + ostree-admin-init-fs1 + + +  Initialize a root filesystem + in a specified path. + + + + + ostree-admin-instutil1 + + +  Utility functions intended primarily for operating system installation programs + + + + + ostree-admin-os-init1 + + +  Initialize the + deployment location for an operating + system with a specified name. + + + + + ostree-admin-status1 + + +  Show and list the deployments. + + + + + ostree-admin-switch1 + + +  Choose a different ref + to track from the same remote as the + current tree. + + + + + ostree-admin-undeploy1 + + +  Remove the previously + INDEX + deployed tree from the bootloader + configuration. + + + + + ostree-admin-upgrade1 + + +  Download the latest version for the + current ref, and deploy it. + + + + + Both administrators and operating system + builders may interact with OSTree via the regular + filesystem manipulation commands. + + + + + ostree-cat1 + + +  Concatenate contents of files + + + + + ostree-checkout1 + + +  Check out a commit into a filesystem tree. + + + + + ostree-checksum1 + + +  Gives checksum of any file. + + + + + ostree-commit1 + + +  Given one or more + trees, create a new commit using those contents. + + + + + ostree-config1 + + +  Change settings. + + + + + ostree-create-usb1 + + +  Put the given refs on an external drive for P2P distribution. + + + + + ostree-diff1 + + +  Concisely list + differences between the given refs. + + + + + ostree-find-remotes1 + + +  Find remotes to serve the given refs. + + + + + ostree-fsck1 + + +  Check a repository for consistency. + + + + + ostree-init1 + + +  Initialize a new repository. + + + + + ostree-log1 + + +  Show revision log. + + + + + ostree-ls1 + + +  List the contents of a given commit. + + + + + ostree-prune1 + + +  Search for unreachable objects. + + + + + ostree-pull-local1 + + +  Copy data from source-repo. + + + + + ostree-pull1 + + +  Download data from remote repo. If you have libsoup. + + + + + ostree-refs1 + + +  List refs. + + + + + ostree-remote1 + + +  Manipulate remote archive configuration. + + + + + ostree-reset1 + + +  Reset a ref to a previous commit. + + + + + ostree-rev-parse1 + + +  Show the SHA256 corresponding to a given rev. + + + + + ostree-show1 + + +  Given an OSTree SHA256 checksum, display its contents. + + + + + ostree-static-delta1 + + +  Manage static delta files. + + + + + ostree-summary1 + + +  Regenerate the repository summary metadata. + + + + + ostree-trivial-httpd1 + + +  Simple webserver. + + + + + + + Examples + + + For specific examples, please see the man page regarding the specific ostree command. For example: + + + man ostree init or man ostree-admin status + + + + + GPG verification + + + OSTree supports signing commits with GPG. Operations on the system + repository by default use keyring files in + /usr/share/ostree/trusted.gpg.d. Any + public key in a keyring file in that directory will be + trusted by the client. No private keys should be present + in this directory. + + + In addition to the system repository, OSTree supports two + other paths. First, there is a + gpgkeypath option for remotes, which must point + to the filename of an ASCII-armored GPG key, or a directory containing + ASCII-armored GPG keys to import. Multiple file and directory paths + to import from can be specified, as a comma-separated list of paths. This option + may be specified by using --set in ostree remote add. + + + Second, there is support for a per-remote + remotename.trustedkeys.gpg + file stored in the toplevel of the repository (alongside + objects/ and such). This is + particularly useful when downloading content that may not + be fully trusted (e.g. you want to inspect it but not + deploy it as an OS), or use it for containers. This file + is written via ostree remote add + --gpg-import. + + + + + See Also + + ostree.repo5 + + + diff --git a/man/rofiles-fuse.xml b/man/rofiles-fuse.xml new file mode 100644 index 0000000..4a48ce9 --- /dev/null +++ b/man/rofiles-fuse.xml @@ -0,0 +1,106 @@ + + + + + + + + + rofiles-fuse + rofiles-fuse + + + + Developer + Colin + Walters + walters@verbum.org + + + + + + rofiles-fuse + 1 + + + + rofiles-fuse + Use FUSE to create a view where directories are writable, files are immutable + + + + + rofiles-fuse SRCDIR MNTPOINT + + + + + Description + + + Creating a checkout from an OSTree repository by default + uses hard links, which means an in-place mutation to any + file corrupts the repository and all checkouts. This can be + problematic if one wishes to run arbitrary programs against + such a checkout. For example, RPM %post + scripts or equivalent. + + + + In the case where one wants to create a tree commit derived + from other content, using rofiles-fuse in + concert with ostree commit + --link-checkout-speedup (or the underlying API) + can ensure that only new files are checksummed. + + + + + + Example: Update an OSTree commit + +# Initialize a checkout and mount +$ ostree --repo=repo checkout somebranch branch-checkout +$ mkdir mnt +$ rofiles-fuse branch-checkout mnt + +# Now, arbitrary changes to mnt/ are reflected in branch-checkout +$ echo somenewcontent > mnt/anewfile +$ mkdir mnt/anewdir +$ rm mnt/someoriginalcontent -rf + +# Commit and cleanup +$ fusermount -u mnt +$ ostree --repo=repo commit --link-checkout-speedup -b somebranch -s 'Commit new content' --tree=dir=branch-checkout +$ rm mnt branch-checkout -rf + + + + + See Also + + ostree1 + + + diff --git a/src/boot/dracut/module-setup.sh b/src/boot/dracut/module-setup.sh new file mode 100755 index 0000000..4d12fae --- /dev/null +++ b/src/boot/dracut/module-setup.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +check() { + if [[ -x $systemdutildir/systemd ]] && [[ -x /usr/lib/ostree/ostree-prepare-root ]]; then + return 255 + fi + + return 1 +} + +depends() { + return 0 +} + +install() { + dracut_install /usr/lib/ostree/ostree-prepare-root + inst_simple "${systemdsystemunitdir}/ostree-prepare-root.service" + mkdir -p "${initdir}${systemdsystemconfdir}/initrd-root-fs.target.wants" + ln_r "${systemdsystemunitdir}/ostree-prepare-root.service" \ + "${systemdsystemconfdir}/initrd-root-fs.target.wants/ostree-prepare-root.service" +} diff --git a/src/boot/dracut/ostree.conf b/src/boot/dracut/ostree.conf new file mode 100755 index 0000000..612bb43 --- /dev/null +++ b/src/boot/dracut/ostree.conf @@ -0,0 +1,18 @@ +# Copyright (C) 2013 Colin Walters +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +add_dracutmodules+=" ostree systemd " diff --git a/src/boot/grub2/grub2-15_ostree b/src/boot/grub2/grub2-15_ostree new file mode 100644 index 0000000..9042708 --- /dev/null +++ b/src/boot/grub2/grub2-15_ostree @@ -0,0 +1,61 @@ +#!/bin/sh +# +# Copyright (C) 2014 Colin Walters +# +# 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 of the licence 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., 59 Temple Place, Suite 330, +# Boston, MA 02111-1307, USA. + +# Gracefully exit if ostree is not installed, or there's +# no system repository initialized. +if ! which ostree >/dev/null 2>/dev/null; then + exit 0 +fi +if ! test -d /ostree/repo; then + exit 0 +fi + +# Gracefully exit if the grub2 configuration has BLS enabled, +# and the installed version has support for the blscfg module. +# Since there is no need to create menu entries for that case. +# See: https://src.fedoraproject.org/rpms/grub2/c/7c2bab5e98d +. /etc/default/grub +if test -f /boot/grub2/.grub2-blscfg-supported && \ + test "${GRUB_ENABLE_BLSCFG}" = "true"; then + exit 0 +fi + +# Make sure we're in the right environment +if ! test -n "${GRUB_DEVICE}"; then + echo "This script must be run as a child of grub2-mkconfig" 1>&2 + exit 1 +fi + +set -e + +# Pick up stuff from grub's helper that we want to inject into our +# generated bootloader configuration. Yes, this is pretty awful, but +# it's a lot better than reimplementing the config-generating bits of +# OSTree in shell script. + +. /usr/share/grub/grub-mkconfig_lib + +DEVICE=${GRUB_DEVICE_BOOT:-${GRUB_DEVICE}} + +GRUB2_BOOT_DEVICE_ID="$(grub_get_device_id ${DEVICE})" +export GRUB2_BOOT_DEVICE_ID +GRUB2_PREPARE_ROOT_CACHE="$(prepare_grub_to_access_device ${DEVICE})" +export GRUB2_PREPARE_ROOT_CACHE + +exec ostree admin instutil grub2-generate diff --git a/src/boot/grub2/ostree-grub-generator b/src/boot/grub2/ostree-grub-generator new file mode 100644 index 0000000..d1436b6 --- /dev/null +++ b/src/boot/grub2/ostree-grub-generator @@ -0,0 +1,115 @@ +#!/bin/sh + +# The builtin grub.cfg generator. This script is called by +# ostree/src/libostree/ostree-bootloader-grub2.c whenever boot loader +# configuration file needs to be updated on systems which do not use +# grub2-mkconfig (and thus, the `ostree admin instutil grub2-generate` path). +# +# It can be used as a template for a custom grub.cfg generator. What to consider +# when writing a custom grub.cfg generator: +# +# - The populate_menu() function converts boot loader entries as defined by +# https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/ into GRUB2 +# menuentry sections. This is the core logic that is required by OSTree +# based system. +# +# - Embedded systems: Be aware that this script is executed not only on a host machine by OS +# installer, but also on a target device, thus think about shell portability. A target device +# for example might be using busybox with a limited shell. +# +# Feel free to edit this script to fit your requirements. + +set -e + +script=$(basename ${0}) +# Atomically safe location where to generete grub.cfg when executing system upgrade. +new_grub2_cfg=${2} +entries_path=$(dirname $new_grub2_cfg)/entries + +read_config() +{ + config_file=${1} + title="" + initrd="" + options="" + linux="" + devicetree="" + + while read -r line + do + record=$(echo ${line} | cut -f 1 -d ' ') + value=$(echo ${line} | cut -s -f2- -d ' ') + case "${record}" in + "title") + title=${value} + ;; + "initrd") + initrd=${value} + ;; + "linux") + linux=${value} + ;; + "devicetree") + devicetree=${value} + ;; + "options") + options=${value} + ;; + esac + done < ${config_file} + + if [ -z "${title}" ]; then + title="(Untitled)" + fi +} + +populate_menu() +{ + # Default to /boot if OSTREE_BOOT_PARTITION is not set and /boot is on the same device as /ostree/repo + if [ -z ${OSTREE_BOOT_PARTITION+x} ] && [ -d /boot/ostree ] && [ -d /ostree/repo ] && [ $(stat -c '%d' /boot/ostree) -eq $(stat -c '%d' /ostree/repo) ]; then + boot_prefix="/boot" + else + boot_prefix="${OSTREE_BOOT_PARTITION}" + fi + for config in $(ls -v -r $entries_path/*.conf); do + read_config ${config} + menu="${menu}menuentry '${title}' {\n" + menu="${menu}\t linux ${boot_prefix}${linux} ${options}\n" + if [ -n "${initrd}" ] ; then + menu="${menu}\t initrd ${boot_prefix}${initrd}\n" + fi + if [ -n "${devicetree}" ] ; then + menu="${menu}\t devicetree ${boot_prefix}${devicetree}\n" + fi + menu="${menu}}\n\n" + done + # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation + printf "$menu" >> ${new_grub2_cfg} +} + +populate_warning() +{ +cat >> ${new_grub2_cfg} <> ${new_grub2_cfg} < +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +[Unit] +Description=OSTree Prepare OS/ +Documentation=man:ostree(1) +DefaultDependencies=no +ConditionKernelCommandLine=ostree +ConditionPathExists=/etc/initrd-release +OnFailure=emergency.target +After=sysroot.mount +Requires=sysroot.mount +Before=initrd-root-fs.target + +[Service] +Type=oneshot +ExecStart=/usr/lib/ostree/ostree-prepare-root /sysroot +StandardInput=null +StandardOutput=syslog +StandardError=syslog+console +RemainAfterExit=yes diff --git a/src/boot/ostree-remount.service b/src/boot/ostree-remount.service new file mode 100644 index 0000000..4c3ed94 --- /dev/null +++ b/src/boot/ostree-remount.service @@ -0,0 +1,42 @@ +# Copyright (C) 2013 Colin Walters +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +[Unit] +Description=OSTree Remount OS/ Bind Mounts +Documentation=man:ostree(1) +DefaultDependencies=no +ConditionKernelCommandLine=ostree +OnFailure=emergency.target +Conflicts=umount.target +# Run after core mounts +After=-.mount var.mount +After=systemd-remount-fs.service +# But we run *before* most other core bootup services that need write access to /etc and /var +Before=local-fs.target umount.target +Before=systemd-random-seed.service plymouth-read-write.service systemd-journal-flush.service +Before=systemd-tmpfiles-setup.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/ostree/ostree-remount +StandardInput=null +StandardOutput=syslog +StandardError=syslog+console + +[Install] +WantedBy=local-fs.target diff --git a/src/boot/ostree-tmpfiles.conf b/src/boot/ostree-tmpfiles.conf new file mode 100644 index 0000000..49e2dcb --- /dev/null +++ b/src/boot/ostree-tmpfiles.conf @@ -0,0 +1,19 @@ +# Copyright (C) 2017 Colin Walters +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# https://github.com/ostreedev/ostree/issues/393 +R! /var/tmp/ostree-unlock-ovl.* diff --git a/src/libostree/README-gpg b/src/libostree/README-gpg new file mode 100644 index 0000000..9c1d479 --- /dev/null +++ b/src/libostree/README-gpg @@ -0,0 +1,2 @@ +Any GPG keyring files ending in ".gpg" placed in this directory will +be automatically trusted by OSTree. diff --git a/src/libostree/bupsplit.c b/src/libostree/bupsplit.c new file mode 100644 index 0000000..79207a6 --- /dev/null +++ b/src/libostree/bupsplit.c @@ -0,0 +1,118 @@ +/* + * Copyright 2011 Avery Pennarun. All rights reserved. + * + * (This license applies to bupsplit.c and bupsplit.h only.) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY AVERY PENNARUN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "bupsplit.h" +#include +#include +#include +#include + +// According to librsync/rollsum.h: +// "We should make this something other than zero to improve the +// checksum algorithm: tridge suggests a prime number." +// apenwarr: I unscientifically tried 0 and 7919, and they both ended up +// slightly worse than the librsync value of 31 for my arbitrary test data. +#define ROLLSUM_CHAR_OFFSET 31 + +typedef struct { + unsigned s1, s2; + uint8_t window[BUP_WINDOWSIZE]; + int wofs; +} Rollsum; + + +// These formulas are based on rollsum.h in the librsync project. +static void rollsum_add(Rollsum *r, uint8_t drop, uint8_t add) +{ + r->s1 += add - drop; + r->s2 += r->s1 - (BUP_WINDOWSIZE * (drop + ROLLSUM_CHAR_OFFSET)); +} + + +static void rollsum_init(Rollsum *r) +{ + r->s1 = BUP_WINDOWSIZE * ROLLSUM_CHAR_OFFSET; + r->s2 = BUP_WINDOWSIZE * (BUP_WINDOWSIZE-1) * ROLLSUM_CHAR_OFFSET; + r->wofs = 0; + memset(r->window, 0, BUP_WINDOWSIZE); +} + + +// For some reason, gcc 4.3 (at least) optimizes badly if find_ofs() +// is static and rollsum_roll is an inline function. Let's use a macro +// here instead to help out the optimizer. +#define rollsum_roll(r, ch) do { \ + rollsum_add((r), (r)->window[(r)->wofs], (ch)); \ + (r)->window[(r)->wofs] = (ch); \ + (r)->wofs = ((r)->wofs + 1) % BUP_WINDOWSIZE; \ +} while (0) + + +static uint32_t rollsum_digest(Rollsum *r) +{ + return (r->s1 << 16) | (r->s2 & 0xffff); +} + + +uint32_t +bupsplit_sum(uint8_t *buf, size_t ofs, size_t len) +{ + size_t count; + Rollsum r; + rollsum_init(&r); + for (count = ofs; count < len; count++) + rollsum_roll(&r, buf[count]); + return rollsum_digest(&r); +} + + +int bupsplit_find_ofs(const unsigned char *buf, int len, int *bits) +{ + Rollsum r; + int count; + + rollsum_init(&r); + for (count = 0; count < len; count++) + { + rollsum_roll(&r, buf[count]); + if ((r.s2 & (BUP_BLOBSIZE-1)) == ((~0) & (BUP_BLOBSIZE-1))) + { + if (bits) + { + unsigned rsum = rollsum_digest(&r); + *bits = BUP_BLOBBITS; + rsum >>= BUP_BLOBBITS; + for (*bits = BUP_BLOBBITS; (rsum >>= 1) & 1; (*bits)++) + ; + } + return count+1; + } + } + return 0; +} diff --git a/src/libostree/bupsplit.h b/src/libostree/bupsplit.h new file mode 100644 index 0000000..f770ee5 --- /dev/null +++ b/src/libostree/bupsplit.h @@ -0,0 +1,52 @@ +/* + * Copyright 2011 Avery Pennarun. All rights reserved. + * + * (This license applies to bupsplit.c and bupsplit.h only.) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY AVERY PENNARUN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __BUPSPLIT_H +#define __BUPSPLIT_H + +#include +#include + +#define BUP_BLOBBITS (13) +#define BUP_BLOBSIZE (1< + + 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 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +***/ + +/* Stub section for the stable release *after* this development one; don't + * edit this other than to update the year. This is just a copy/paste + * source. Replace $LASTSTABLE with the last stable version, and $NEWVERSION + * with whatever the next version with new symbols will be. +LIBOSTREE_2020.$NEWVERSION { +global: + someostree_symbol_deleteme; +} LIBOSTREE_2020.$LASTSTABLE; +*/ diff --git a/src/libostree/libostree-released.sym b/src/libostree/libostree-released.sym new file mode 100644 index 0000000..5c63f78 --- /dev/null +++ b/src/libostree/libostree-released.sym @@ -0,0 +1,622 @@ +/* Released symbol file: DO NOT EDIT except in release commits! + Edit libostree-devel.sym instead. + + Copyright (C) 2016 Colin Walters + + 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 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +***/ + +/* DO NOT EDIT this file - use libostree-devel.sym instead. Release + * commits will move symbols from libostree-devel.sym to libostree-released.sym. + */ + +/* + Retroactively make all of these symbols 2016.3, which is + the first release where we started using versioned symbols. See + also https://www.berrange.com/posts/2011/01/13/versioning-in-the-libvirt-library/ + */ +LIBOSTREE_2016.3 { +global: + ostree_async_progress_finish; + ostree_async_progress_get_status; + ostree_async_progress_get_type; + ostree_async_progress_get_uint; + ostree_async_progress_get_uint64; + ostree_async_progress_new; + ostree_async_progress_new_and_connect; + ostree_async_progress_set_status; + ostree_async_progress_set_uint; + ostree_async_progress_set_uint64; + ostree_bootconfig_parser_clone; + ostree_bootconfig_parser_get; + ostree_bootconfig_parser_get_type; + ostree_bootconfig_parser_new; + ostree_bootconfig_parser_parse; + ostree_bootconfig_parser_parse_at; + ostree_bootconfig_parser_set; + ostree_bootconfig_parser_write; + ostree_bootconfig_parser_write_at; + ostree_chain_input_stream_get_type; + ostree_chain_input_stream_new; + ostree_checksum_b64_inplace_from_bytes; + ostree_checksum_b64_inplace_to_bytes; + ostree_checksum_bytes_peek; + ostree_checksum_bytes_peek_validate; + ostree_checksum_file; + ostree_checksum_file_async; + ostree_checksum_file_async_finish; + ostree_checksum_file_from_input; + ostree_checksum_from_bytes; + ostree_checksum_from_bytes_v; + ostree_checksum_inplace_from_bytes; + ostree_checksum_inplace_to_bytes; + ostree_checksum_input_stream_get_type; + ostree_checksum_input_stream_new; + ostree_checksum_to_bytes; + ostree_checksum_to_bytes_v; + ostree_cmd__private__; + ostree_cmp_checksum_bytes; + ostree_commit_get_parent; + ostree_commit_get_timestamp; + ostree_content_file_parse; + ostree_content_file_parse_at; + ostree_content_stream_parse; + ostree_create_directory_metadata; + ostree_deployment_clone; + ostree_deployment_equal; + ostree_deployment_get_bootconfig; + ostree_deployment_get_bootcsum; + ostree_deployment_get_bootserial; + ostree_deployment_get_csum; + ostree_deployment_get_deployserial; + ostree_deployment_get_index; + ostree_deployment_get_origin; + ostree_deployment_get_origin_relpath; + ostree_deployment_get_osname; + ostree_deployment_get_type; + ostree_deployment_hash; + ostree_deployment_new; + ostree_deployment_set_bootconfig; + ostree_deployment_set_bootserial; + ostree_deployment_set_index; + ostree_deployment_set_origin; + ostree_diff_dirs; + ostree_diff_item_get_type; + ostree_diff_item_ref; + ostree_diff_item_unref; + ostree_diff_print; + ostree_fetcher_config_flags_get_type; + ostree_gpg_verify_result_count_all; + ostree_gpg_verify_result_count_valid; + ostree_gpg_verify_result_describe; + ostree_gpg_verify_result_describe_variant; + ostree_gpg_verify_result_get; + ostree_gpg_verify_result_get_all; + ostree_gpg_verify_result_get_type; + ostree_gpg_verify_result_lookup; + ostree_hash_object_name; + ostree_metadata_variant_type; + ostree_mutable_tree_ensure_dir; + ostree_mutable_tree_ensure_parent_dirs; + ostree_mutable_tree_get_contents_checksum; + ostree_mutable_tree_get_files; + ostree_mutable_tree_get_metadata_checksum; + ostree_mutable_tree_get_subdirs; + ostree_mutable_tree_get_type; + ostree_mutable_tree_lookup; + ostree_mutable_tree_new; + ostree_mutable_tree_replace_file; + ostree_mutable_tree_set_contents_checksum; + ostree_mutable_tree_set_metadata_checksum; + ostree_mutable_tree_walk; + ostree_object_from_string; + ostree_object_name_deserialize; + ostree_object_name_serialize; + ostree_object_to_string; + ostree_object_type_from_string; + ostree_object_type_to_string; + ostree_parse_refspec; + ostree_raw_file_to_content_stream; + ostree_repo_abort_transaction; + ostree_repo_add_gpg_signature_summary; + ostree_repo_append_gpg_signature; + ostree_repo_checkout_gc; + ostree_repo_checkout_tree; + ostree_repo_checkout_tree_at; + ostree_repo_commit_modifier_get_type; + ostree_repo_commit_modifier_new; + ostree_repo_commit_modifier_ref; + ostree_repo_commit_modifier_set_devino_cache; + ostree_repo_commit_modifier_set_sepolicy; + ostree_repo_commit_modifier_set_xattr_callback; + ostree_repo_commit_modifier_unref; + ostree_repo_commit_transaction; + ostree_repo_commit_traverse_iter_cleanup; + ostree_repo_commit_traverse_iter_clear; + ostree_repo_commit_traverse_iter_get_dir; + ostree_repo_commit_traverse_iter_get_file; + ostree_repo_commit_traverse_iter_init_commit; + ostree_repo_commit_traverse_iter_init_dirtree; + ostree_repo_commit_traverse_iter_next; + ostree_repo_copy_config; + ostree_repo_create; + ostree_repo_delete_object; + ostree_repo_devino_cache_get_type; + ostree_repo_devino_cache_new; + ostree_repo_devino_cache_ref; + ostree_repo_devino_cache_unref; + ostree_repo_export_tree_to_archive; + ostree_repo_file_ensure_resolved; + ostree_repo_file_get_checksum; + ostree_repo_file_get_repo; + ostree_repo_file_get_root; + ostree_repo_file_get_type; + ostree_repo_file_get_xattrs; + ostree_repo_file_tree_find_child; + ostree_repo_file_tree_get_contents; + ostree_repo_file_tree_get_contents_checksum; + ostree_repo_file_tree_get_metadata; + ostree_repo_file_tree_get_metadata_checksum; + ostree_repo_file_tree_query_child; + ostree_repo_file_tree_set_metadata; + ostree_repo_get_config; + ostree_repo_get_disable_fsync; + ostree_repo_get_mode; + ostree_repo_get_parent; + ostree_repo_get_path; + ostree_repo_get_type; + ostree_repo_has_object; + ostree_repo_import_archive_to_mtree; + ostree_repo_import_object_from; + ostree_repo_is_system; + ostree_repo_is_writable; + ostree_repo_list_commit_objects_starting_with; + ostree_repo_list_objects; + ostree_repo_list_refs; + ostree_repo_list_static_delta_names; + ostree_repo_load_commit; + ostree_repo_load_file; + ostree_repo_load_object_stream; + ostree_repo_load_variant; + ostree_repo_load_variant_if_exists; + ostree_repo_mode_from_string; + ostree_repo_new; + ostree_repo_new_default; + ostree_repo_new_for_sysroot_path; + ostree_repo_open; + ostree_repo_prepare_transaction; + ostree_repo_prune; + ostree_repo_prune_static_deltas; + ostree_repo_pull; + ostree_repo_pull_default_console_progress_changed; + ostree_repo_pull_one_dir; + ostree_repo_pull_with_options; + ostree_repo_query_object_storage_size; + ostree_repo_read_commit; + ostree_repo_read_commit_detached_metadata; + ostree_repo_regenerate_summary; + ostree_repo_remote_add; + ostree_repo_remote_change; + ostree_repo_remote_delete; + ostree_repo_remote_fetch_summary; + ostree_repo_remote_get_gpg_verify; + ostree_repo_remote_get_gpg_verify_summary; + ostree_repo_remote_get_url; + ostree_repo_remote_gpg_import; + ostree_repo_remote_list; + ostree_repo_remote_list_refs; + ostree_repo_resolve_rev; + ostree_repo_scan_hardlinks; + ostree_repo_set_disable_fsync; + ostree_repo_set_ref_immediate; + ostree_repo_sign_commit; + ostree_repo_sign_delta; + ostree_repo_static_delta_execute_offline; + ostree_repo_static_delta_generate; + ostree_repo_transaction_set_ref; + ostree_repo_transaction_set_refspec; + ostree_repo_transaction_stats_get_type; + ostree_repo_traverse_commit; + ostree_repo_traverse_commit_union; + ostree_repo_traverse_new_reachable; + ostree_repo_verify_commit; + ostree_repo_verify_commit_ext; + ostree_repo_verify_summary; + ostree_repo_write_archive_to_mtree; + ostree_repo_write_commit; + ostree_repo_write_commit_detached_metadata; + ostree_repo_write_commit_with_time; + ostree_repo_write_config; + ostree_repo_write_content; + ostree_repo_write_content_async; + ostree_repo_write_content_finish; + ostree_repo_write_content_trusted; + ostree_repo_write_dfd_to_mtree; + ostree_repo_write_directory_to_mtree; + ostree_repo_write_metadata; + ostree_repo_write_metadata_async; + ostree_repo_write_metadata_finish; + ostree_repo_write_metadata_stream_trusted; + ostree_repo_write_metadata_trusted; + ostree_repo_write_mtree; + ostree_sepolicy_fscreatecon_cleanup; + ostree_sepolicy_get_label; + ostree_sepolicy_get_name; + ostree_sepolicy_get_path; + ostree_sepolicy_get_type; + ostree_sepolicy_new; + ostree_sepolicy_restorecon; + ostree_sepolicy_setfscreatecon; + ostree_sysroot_cleanup; + ostree_sysroot_deployment_set_kargs; + ostree_sysroot_deployment_set_mutable; + ostree_sysroot_deploy_tree; + ostree_sysroot_ensure_initialized; + ostree_sysroot_get_booted_deployment; + ostree_sysroot_get_bootversion; + ostree_sysroot_get_deployment_directory; + ostree_sysroot_get_deployment_dirpath; + ostree_sysroot_get_deployment_origin_path; + ostree_sysroot_get_deployments; + ostree_sysroot_get_fd; + ostree_sysroot_get_merge_deployment; + ostree_sysroot_get_path; + ostree_sysroot_get_repo; + ostree_sysroot_get_subbootversion; + ostree_sysroot_get_type; + ostree_sysroot_load; + ostree_sysroot_lock; + ostree_sysroot_lock_async; + ostree_sysroot_lock_finish; + ostree_sysroot_new; + ostree_sysroot_new_default; + ostree_sysroot_origin_new_from_refspec; + ostree_sysroot_prepare_cleanup; + ostree_sysroot_simple_write_deployment; + ostree_sysroot_try_lock; + ostree_sysroot_unload; + ostree_sysroot_unlock; + ostree_sysroot_upgrader_check_timestamps; + ostree_sysroot_upgrader_deploy; + ostree_sysroot_upgrader_dup_origin; + ostree_sysroot_upgrader_flags_get_type; + ostree_sysroot_upgrader_get_origin; + ostree_sysroot_upgrader_get_origin_description; + ostree_sysroot_upgrader_get_type; + ostree_sysroot_upgrader_new; + ostree_sysroot_upgrader_new_for_os; + ostree_sysroot_upgrader_new_for_os_with_flags; + ostree_sysroot_upgrader_pull; + ostree_sysroot_upgrader_pull_one_dir; + ostree_sysroot_upgrader_set_origin; + ostree_sysroot_write_deployments; + ostree_sysroot_write_origin_file; + ostree_validate_checksum_string; + ostree_validate_rev; + ostree_validate_structureof_checksum_string; + ostree_validate_structureof_commit; + ostree_validate_structureof_csum_v; + ostree_validate_structureof_dirmeta; + ostree_validate_structureof_dirtree; + ostree_validate_structureof_file_mode; + ostree_validate_structureof_objtype; +local: + *; +}; + +LIBOSTREE_2016.4 { +global: + ostree_repo_get_dfd; + ostree_repo_list_refs_ext; + ostree_sysroot_init_osname; + ostree_sysroot_load_if_changed; + ostree_sysroot_deployment_unlock; + ostree_deployment_get_unlocked; + ostree_deployment_unlocked_state_to_string; +} LIBOSTREE_2016.3; + +LIBOSTREE_2016.5 { +global: + ostree_repo_import_object_from_with_trust; + ostree_sepolicy_get_csum; + ostree_repo_get_remote_option; + ostree_repo_get_remote_list_option; + ostree_repo_get_remote_boolean_option; + ostree_repo_set_cache_dir; +} LIBOSTREE_2016.4; + +LIBOSTREE_2016.6 { +global: + ostree_gpg_verify_result_require_valid_signature; + ostree_raw_file_to_archive_z2_stream; + ostree_repo_gpg_verify_data; + ostree_repo_remote_fetch_summary_with_options; +} LIBOSTREE_2016.5; + +LIBOSTREE_2016.7 { +global: + ostree_repo_resolve_rev_ext; +} LIBOSTREE_2016.6; + +LIBOSTREE_2016.8 { +global: + ostree_checksum_b64_to_bytes; + ostree_checksum_b64_from_bytes; + ostree_repo_checkout_at; +} LIBOSTREE_2016.7; + +/* No new symbols in 2016.9 */ +/* No new symbols in 2016.10 */ +/* No new symbols in 2016.11 */ +/* No new symbols in 2016.12 */ +/* No new symbols in 2016.13 */ + +LIBOSTREE_2016.14 { +global: + ostree_repo_verify_commit_for_remote; +} LIBOSTREE_2016.8; + +/* No new symbols in 2016.15 */ + +LIBOSTREE_2017.1 { +global: + ostree_repo_prune_from_reachable; +} LIBOSTREE_2016.14; + +LIBOSTREE_2017.2 { +global: + ostree_repo_reload_config; +} LIBOSTREE_2017.1; + +LIBOSTREE_2017.3 { +global: + ostree_raw_file_to_archive_z2_stream_with_options; +} LIBOSTREE_2017.2; + +LIBOSTREE_2017.4 { +global: + ostree_check_version; + ostree_diff_dirs_with_options; + ostree_sepolicy_new_at; + ostree_sysroot_write_deployments_with_options; +} LIBOSTREE_2017.3; + +LIBOSTREE_2017.6 { +global: + ostree_async_progress_get; + ostree_async_progress_set; + ostree_async_progress_get_variant; + ostree_async_progress_set_variant; +} LIBOSTREE_2017.4; + +LIBOSTREE_2017.7 { +global: + ostree_sysroot_repo; + ostree_sysroot_query_deployments_for; +} LIBOSTREE_2017.6; + +LIBOSTREE_2017.8 { +global: + ostree_validate_remote_name; +} LIBOSTREE_2017.7; + +LIBOSTREE_2017.9 { +}; + +LIBOSTREE_2017.10 { + ostree_gpg_error_quark; + ostree_repo_set_alias_ref_immediate; + ostree_repo_open_at; + ostree_repo_create_at; +/* Inherit from .8 since .9 is empty and is also broken + * in that it doesn't have a parent currently; + * + */ +} LIBOSTREE_2017.8; + +LIBOSTREE_2017.11 { +} LIBOSTREE_2017.10; + +LIBOSTREE_2017.12 { +global: + ostree_repo_equal; + ostree_repo_hash; +} LIBOSTREE_2017.11; + +LIBOSTREE_2017.13 { +global: + ostree_checksum_file_at; + ostree_repo_checkout_at_options_set_devino; +} LIBOSTREE_2017.12; + +LIBOSTREE_2017.14 { +} LIBOSTREE_2017.13; + +LIBOSTREE_2017.15 { + ostree_repo_fsck_object; + ostree_repo_mark_commit_partial; + ostree_break_hardlink; +} LIBOSTREE_2017.14; + +LIBOSTREE_2018.1 { +} LIBOSTREE_2017.15; + +LIBOSTREE_2018.2 { + ostree_commit_get_content_checksum; +} LIBOSTREE_2018.1; + +LIBOSTREE_2018.3 { + ostree_deployment_origin_remove_transient_state; + ostree_sysroot_deployment_set_pinned; + ostree_deployment_is_pinned; +} LIBOSTREE_2018.2; + +LIBOSTREE_2018.5 { + ostree_sysroot_stage_tree; + ostree_sysroot_get_staged_deployment; + ostree_deployment_is_staged; + ostree_repo_traverse_new_parents; + ostree_repo_traverse_parents_get_commits; + ostree_repo_traverse_commit_union_with_parents; +} LIBOSTREE_2018.3; + +LIBOSTREE_2018.6 { +global: + ostree_collection_ref_dup; + ostree_collection_ref_dupv; + ostree_collection_ref_equal; + ostree_collection_ref_free; + ostree_collection_ref_freev; + ostree_collection_ref_get_type; + ostree_collection_ref_hash; + ostree_collection_ref_new; + ostree_remote_get_name; + ostree_remote_get_type; + ostree_remote_get_url; + ostree_remote_ref; + ostree_remote_unref; + ostree_repo_find_remotes_async; + ostree_repo_find_remotes_finish; + ostree_repo_finder_avahi_get_type; + ostree_repo_finder_avahi_new; + ostree_repo_finder_avahi_start; + ostree_repo_finder_avahi_stop; + ostree_repo_finder_config_get_type; + ostree_repo_finder_config_new; + ostree_repo_finder_get_type; + ostree_repo_finder_mount_get_type; + ostree_repo_finder_mount_new; + ostree_repo_finder_override_add_uri; + ostree_repo_finder_override_get_type; + ostree_repo_finder_override_new; + ostree_repo_finder_resolve_all_async; + ostree_repo_finder_resolve_all_finish; + ostree_repo_finder_resolve_async; + ostree_repo_finder_resolve_finish; + ostree_repo_finder_result_compare; + ostree_repo_finder_result_dup; + ostree_repo_finder_result_free; + ostree_repo_finder_result_freev; + ostree_repo_finder_result_get_type; + ostree_repo_finder_result_new; + ostree_repo_get_collection_id; + ostree_repo_list_collection_refs; + ostree_repo_pull_from_remotes_async; + ostree_repo_pull_from_remotes_finish; + ostree_repo_remote_list_collection_refs; + ostree_repo_resolve_collection_ref; + ostree_repo_resolve_keyring_for_collection; + ostree_repo_set_collection_id; + ostree_repo_set_collection_ref_immediate; + ostree_repo_transaction_set_collection_ref; + ostree_repo_traverse_reachable_refs; + ostree_sysroot_cleanup_prune_repo; + ostree_validate_collection_id; +} LIBOSTREE_2018.5; + +LIBOSTREE_2018.7 { +global: + ostree_mutable_tree_fill_empty_from_dirtree; + ostree_mutable_tree_new_from_checksum; + ostree_mutable_tree_check_error; +} LIBOSTREE_2018.6; + +/* No new symbols in 2018.8 */ + +LIBOSTREE_2018.9 { + ostree_mutable_tree_remove; + ostree_repo_get_min_free_space_bytes; + ostree_repo_get_default_repo_finders; +} LIBOSTREE_2018.7; + +/* No new symbols in 2019.1 */ + +LIBOSTREE_2019.2 { + ostree_repo_get_bootloader; +} LIBOSTREE_2018.9; + +LIBOSTREE_2019.3 { +global: + ostree_repo_write_archive_to_mtree_from_fd; + ostree_kernel_args_free; + ostree_kernel_args_new; + ostree_kernel_args_cleanup; + ostree_kernel_args_replace_take; + ostree_kernel_args_replace; + ostree_kernel_args_replace_argv; + ostree_kernel_args_append; + ostree_kernel_args_append_argv; + ostree_kernel_args_append_argv_filtered; + ostree_kernel_args_new_replace; + ostree_kernel_args_delete; + ostree_kernel_args_delete_key_entry; + ostree_kernel_args_append_proc_cmdline; + ostree_kernel_args_parse_append; + ostree_kernel_args_get_last_value; + ostree_kernel_args_from_string; + ostree_kernel_args_to_strv; + ostree_kernel_args_to_string; +} LIBOSTREE_2018.9; + +LIBOSTREE_2019.4 { + ostree_repo_mark_commit_partial_reason; +} LIBOSTREE_2019.3; + +/* No new symbols in 2019.5 */ + +LIBOSTREE_2019.6 { + ostree_async_progress_copy_state; +} LIBOSTREE_2019.4; + +LIBOSTREE_2020.1 { +global: + ostree_commit_get_object_sizes; + ostree_commit_sizes_entry_copy; + ostree_commit_sizes_entry_free; + ostree_commit_sizes_entry_get_type; + ostree_commit_sizes_entry_new; + ostree_sysroot_initialize; + ostree_sysroot_is_booted; + ostree_sysroot_set_mount_namespace_in_use; +} LIBOSTREE_2019.6; + +/* Add new symbols here. Release commits should copy this section into -released.sym. */ +LIBOSTREE_2020.4 { +global: + ostree_repo_commit_modifier_set_sepolicy_from_commit; + ostree_sign_get_type; + ostree_sign_get_all; + ostree_sign_commit; + ostree_sign_commit_verify; + ostree_sign_data; + ostree_sign_data_verify; + ostree_sign_get_by_name; + ostree_sign_get_name; + ostree_sign_clear_keys; + ostree_sign_load_pk; + ostree_sign_metadata_format; + ostree_sign_metadata_key; + ostree_sign_set_pk; + ostree_sign_add_pk; + ostree_sign_set_sk; + ostree_sign_summary; +} LIBOSTREE_2020.1; + +/* No new symbols in 2020.2 */ + +/* NOTE: Only add more content here in release commits! See the + * comments at the top of this file. + */ diff --git a/src/libostree/ostree-1.pc.in b/src/libostree/ostree-1.pc.in new file mode 100644 index 0000000..9a4debc --- /dev/null +++ b/src/libostree/ostree-1.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +features=@OSTREE_FEATURES@ + +Name: OSTree +Description: Git for operating system binaries +Version: @VERSION@ +Requires: gio-unix-2.0 +Libs: -L${libdir} -lostree-1 +Cflags: -I${includedir}/ostree-1 diff --git a/src/libostree/ostree-async-progress.c b/src/libostree/ostree-async-progress.c new file mode 100644 index 0000000..8d6fdfe --- /dev/null +++ b/src/libostree/ostree-async-progress.c @@ -0,0 +1,510 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-async-progress.h" + +#include "libglnx.h" + +/** + * SECTION:ostree-async-progress + * @title: Progress notification system for asynchronous operations + * @short_description: Values representing progress + * + * For many asynchronous operations, it's desirable for callers to be + * able to watch their status as they progress. For example, an user + * interface calling an asynchronous download operation will want to + * be able to see the total number of bytes downloaded. + * + * This class provides a mechanism for callees of asynchronous + * operations to communicate back with callers. It transparently + * handles thread safety, ensuring that the progress change + * notification occurs in the thread-default context of the calling + * operation. + * + * The ostree_async_progress_get_status() and ostree_async_progress_set_status() + * methods get and set a well-known `status` key of type %G_VARIANT_TYPE_STRING. + * This key may be accessed using the other #OstreeAsyncProgress methods, but it + * must always have the correct type. + */ + +enum { + CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +struct OstreeAsyncProgress +{ + GObject parent_instance; + + GMutex lock; + GMainContext *maincontext; + GSource *idle_source; + GHashTable *values; /* (element-type uint GVariant) */ + + gboolean dead; +}; + +G_DEFINE_TYPE (OstreeAsyncProgress, ostree_async_progress, G_TYPE_OBJECT) + +static void +ostree_async_progress_finalize (GObject *object) +{ + OstreeAsyncProgress *self; + + self = OSTREE_ASYNC_PROGRESS (object); + + g_mutex_clear (&self->lock); + g_clear_pointer (&self->maincontext, g_main_context_unref); + g_clear_pointer (&self->idle_source, g_source_unref); + g_hash_table_unref (self->values); + + G_OBJECT_CLASS (ostree_async_progress_parent_class)->finalize (object); +} + +static void +ostree_async_progress_class_init (OstreeAsyncProgressClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = ostree_async_progress_finalize; + + /** + * OstreeAsyncProgress::changed: + * @self: Self + * + * Emitted when @self has been changed. + **/ + signals[CHANGED] = + g_signal_new ("changed", + OSTREE_TYPE_ASYNC_PROGRESS, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (OstreeAsyncProgressClass, changed), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); +} + +static void +ostree_async_progress_init (OstreeAsyncProgress *self) +{ + g_mutex_init (&self->lock); + self->maincontext = g_main_context_ref_thread_default (); + self->values = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_variant_unref); +} + +/** + * ostree_async_progress_get_variant: + * @self: an #OstreeAsyncProgress + * @key: a key to look up + * + * Look up a key in the #OstreeAsyncProgress and return the #GVariant associated + * with it. The lookup is thread-safe. + * + * Returns: (transfer full) (nullable): value for the given @key, or %NULL if + * it was not set + * Since: 2017.6 + */ +GVariant * +ostree_async_progress_get_variant (OstreeAsyncProgress *self, + const char *key) +{ + GVariant *rval; + + g_return_val_if_fail (OSTREE_IS_ASYNC_PROGRESS (self), NULL); + g_return_val_if_fail (key != NULL, NULL); + + g_mutex_lock (&self->lock); + rval = g_hash_table_lookup (self->values, GUINT_TO_POINTER (g_quark_from_string (key))); + if (rval != NULL) + g_variant_ref (rval); + g_mutex_unlock (&self->lock); + + return rval; +} + +guint +ostree_async_progress_get_uint (OstreeAsyncProgress *self, + const char *key) +{ + g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, key); + return (rval != NULL) ? g_variant_get_uint32 (rval) : 0; +} + +guint64 +ostree_async_progress_get_uint64 (OstreeAsyncProgress *self, + const char *key) +{ + g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, key); + return (rval != NULL) ? g_variant_get_uint64 (rval) : 0; +} + +/** + * ostree_async_progress_get: + * @self: an #OstreeAsyncProgress + * @...: key name, format string, #GVariant return locations, …, followed by %NULL + * + * Get the values corresponding to zero or more keys from the + * #OstreeAsyncProgress. Each key is specified in @... as the key name, followed + * by a #GVariant format string, followed by the necessary arguments for that + * format string, just as for g_variant_get(). After those arguments is the + * next key name. The varargs list must be %NULL-terminated. + * + * Each format string must make deep copies of its value, as the values stored + * in the #OstreeAsyncProgress may be freed from another thread after this + * function returns. + * + * This operation is thread-safe, and all the keys are queried atomically. + * + * |[ + * guint32 outstanding_fetches; + * guint64 bytes_received; + * g_autofree gchar *status = NULL; + * g_autoptr(GVariant) refs_variant = NULL; + * + * ostree_async_progress_get (progress, + * "outstanding-fetches", "u", &outstanding_fetches, + * "bytes-received", "t", &bytes_received, + * "status", "s", &status, + * "refs", "@a{ss}", &refs_variant, + * NULL); + * ]| + * + * Since: 2017.6 + */ +void +ostree_async_progress_get (OstreeAsyncProgress *self, + ...) +{ + va_list ap; + const char *key, *format_string; + + g_mutex_lock (&self->lock); + va_start (ap, self); + + for (key = va_arg (ap, const char *), format_string = va_arg (ap, const char *); + key != NULL; + key = va_arg (ap, const char *), format_string = va_arg (ap, const char *)) + { + GVariant *variant; + + g_assert (format_string != NULL); + + variant = g_hash_table_lookup (self->values, GUINT_TO_POINTER (g_quark_from_string (key))); + g_assert (variant != NULL); + g_assert (g_variant_check_format_string (variant, format_string, TRUE)); + + g_variant_get_va (variant, format_string, NULL, &ap); + } + + va_end (ap); + g_mutex_unlock (&self->lock); +} + +static gboolean +idle_invoke_async_progress (gpointer user_data) +{ + OstreeAsyncProgress *self = user_data; + + g_mutex_lock (&self->lock); + g_clear_pointer (&self->idle_source, g_source_unref); + g_mutex_unlock (&self->lock); + + g_signal_emit (self, signals[CHANGED], 0); + + return FALSE; +} + +static void +ensure_callback_locked (OstreeAsyncProgress *self) +{ + if (self->idle_source) + return; + self->idle_source = g_idle_source_new (); + g_source_set_callback (self->idle_source, idle_invoke_async_progress, self, NULL); + g_source_attach (self->idle_source, self->maincontext); +} + +/** + * ostree_async_progress_set_status: + * @self: an #OstreeAsyncProgress + * @status: (nullable): new status string, or %NULL to clear the status + * + * Set the human-readable status string for the #OstreeAsyncProgress. This + * operation is thread-safe. %NULL may be passed to clear the status. + * + * This is a convenience function to set the well-known `status` key. + * + * Since: 2017.6 + */ +void +ostree_async_progress_set_status (OstreeAsyncProgress *self, + const char *status) +{ + ostree_async_progress_set_variant (self, "status", + g_variant_new_string ((status != NULL) ? status : "")); +} + +/** + * ostree_async_progress_get_status: + * @self: an #OstreeAsyncProgress + * + * Get the human-readable status string from the #OstreeAsyncProgress. This + * operation is thread-safe. The retuned value may be %NULL if no status is + * set. + * + * This is a convenience function to get the well-known `status` key. + * + * Returns: (transfer full) (nullable): the current status, or %NULL if none is set + * Since: 2017.6 + */ +char * +ostree_async_progress_get_status (OstreeAsyncProgress *self) +{ + g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, "status"); + const gchar *status = (rval != NULL) ? g_variant_get_string (rval, NULL) : NULL; + if (status != NULL && *status == '\0') + status = NULL; + return g_strdup (status); +} + +/** + * ostree_async_progress_set: + * @self: an #OstreeAsyncProgress + * @...: key name, format string, #GVariant parameters, …, followed by %NULL + * + * Set the values for zero or more keys in the #OstreeAsyncProgress. Each key is + * specified in @... as the key name, followed by a #GVariant format string, + * followed by the necessary arguments for that format string, just as for + * g_variant_new(). After those arguments is the next key name. The varargs list + * must be %NULL-terminated. + * + * g_variant_ref_sink() will be called as appropriate on the #GVariant + * parameters, so they may be floating. + * + * This operation is thread-safe, and all the keys are set atomically. + * + * |[ + * guint32 outstanding_fetches = 15; + * guint64 bytes_received = 1000; + * + * ostree_async_progress_set (progress, + * "outstanding-fetches", "u", outstanding_fetches, + * "bytes-received", "t", bytes_received, + * "status", "s", "Updated status", + * "refs", "@a{ss}", g_variant_new_parsed ("@a{ss} {}"), + * NULL); + * ]| + * + * Since: 2017.6 + */ +void +ostree_async_progress_set (OstreeAsyncProgress *self, + ...) +{ + va_list ap; + const char *key, *format_string; + gboolean changed; + + g_mutex_lock (&self->lock); + + if (self->dead) + goto out; + + changed = FALSE; + + va_start (ap, self); + + for (key = va_arg (ap, const char *), format_string = va_arg (ap, const char *); + key != NULL; + key = va_arg (ap, const char *), format_string = va_arg (ap, const char *)) + { + GVariant *orig_value; + g_autoptr(GVariant) new_value = NULL; + gpointer qkey = GUINT_TO_POINTER (g_quark_from_string (key)); + + new_value = g_variant_ref_sink (g_variant_new_va (format_string, NULL, &ap)); + + if (g_hash_table_lookup_extended (self->values, qkey, NULL, (gpointer *) &orig_value) && + g_variant_equal (orig_value, new_value)) + continue; + + g_hash_table_replace (self->values, qkey, g_steal_pointer (&new_value)); + changed = TRUE; + } + + va_end (ap); + + if (changed) + ensure_callback_locked (self); + +out: + g_mutex_unlock (&self->lock); +} + +/** + * ostree_async_progress_set_variant: + * @self: an #OstreeAsyncProgress + * @key: a key to set + * @value: the value to assign to @key + * + * Assign a new @value to the given @key, replacing any existing value. The + * operation is thread-safe. @value may be a floating reference; + * g_variant_ref_sink() will be called on it. + * + * Any watchers of the #OstreeAsyncProgress will be notified of the change if + * @value differs from the existing value for @key. + * + * Since: 2017.6 + */ +void +ostree_async_progress_set_variant (OstreeAsyncProgress *self, + const char *key, + GVariant *value) +{ + GVariant *orig_value; + g_autoptr(GVariant) new_value = g_variant_ref_sink (value); + gpointer qkey = GUINT_TO_POINTER (g_quark_from_string (key)); + + g_return_if_fail (OSTREE_IS_ASYNC_PROGRESS (self)); + g_return_if_fail (key != NULL); + g_return_if_fail (value != NULL); + + g_mutex_lock (&self->lock); + + if (self->dead) + goto out; + + if (g_hash_table_lookup_extended (self->values, qkey, NULL, (gpointer *) &orig_value)) + { + if (g_variant_equal (orig_value, new_value)) + goto out; + } + g_hash_table_replace (self->values, qkey, g_steal_pointer (&new_value)); + ensure_callback_locked (self); + + out: + g_mutex_unlock (&self->lock); +} + +void +ostree_async_progress_set_uint (OstreeAsyncProgress *self, + const char *key, + guint value) +{ + ostree_async_progress_set_variant (self, key, g_variant_new_uint32 (value)); +} + +void +ostree_async_progress_set_uint64 (OstreeAsyncProgress *self, + const char *key, + guint64 value) +{ + ostree_async_progress_set_variant (self, key, g_variant_new_uint64 (value)); +} + +/** + * ostree_async_progress_copy_state: + * @self: An #OstreeAsyncProgress to copy from + * @dest: An #OstreeAsyncProgress to copy to + * + * Atomically copies all the state from @self to @dest, without invoking the + * callback. + * This is used for proxying progress objects across different #GMainContexts. + * + * Since: 2019.6 + */ +void +ostree_async_progress_copy_state (OstreeAsyncProgress *self, + OstreeAsyncProgress *dest) +{ + g_return_if_fail (OSTREE_IS_ASYNC_PROGRESS (self)); + g_return_if_fail (OSTREE_IS_ASYNC_PROGRESS (dest)); + + g_mutex_lock (&self->lock); + + if (self->dead) + goto out; + + GLNX_HASH_TABLE_FOREACH_KV (self->values, void *, key, GVariant *, value) + { + if (value) + g_variant_ref (value); + g_hash_table_replace (dest->values, key, value); + } + + out: + g_mutex_unlock (&self->lock); +} + +/** + * ostree_async_progress_new: + * + * Returns: (transfer full): A new progress object + */ +OstreeAsyncProgress * +ostree_async_progress_new (void) +{ + return (OstreeAsyncProgress*)g_object_new (OSTREE_TYPE_ASYNC_PROGRESS, NULL); +} + + +OstreeAsyncProgress * +ostree_async_progress_new_and_connect (void (*changed) (OstreeAsyncProgress *self, gpointer user_data), + gpointer user_data) +{ + OstreeAsyncProgress *ret = ostree_async_progress_new (); + g_signal_connect (ret, "changed", G_CALLBACK (changed), user_data); + return ret; +} + +/** + * ostree_async_progress_finish: + * @self: Self + * + * Process any pending signals, ensuring the main context is cleared + * of sources used by this object. Also ensures that no further + * events will be queued. + */ +void +ostree_async_progress_finish (OstreeAsyncProgress *self) +{ + gboolean emit_changed = FALSE; + + g_mutex_lock (&self->lock); + if (!self->dead) + { + self->dead = TRUE; + if (self->idle_source) + { + g_source_destroy (self->idle_source); + g_clear_pointer (&self->idle_source, g_source_unref); + emit_changed = TRUE; + } + } + g_mutex_unlock (&self->lock); + + if (emit_changed) + g_signal_emit (self, signals[CHANGED], 0); +} diff --git a/src/libostree/ostree-async-progress.h b/src/libostree/ostree-async-progress.h new file mode 100644 index 0000000..475d7f6 --- /dev/null +++ b/src/libostree/ostree-async-progress.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_ASYNC_PROGRESS (ostree_async_progress_get_type ()) +#define OSTREE_ASYNC_PROGRESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_ASYNC_PROGRESS, OstreeAsyncProgress)) +#define OSTREE_ASYNC_PROGRESS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_ASYNC_PROGRESS, OstreeAsyncProgressClass)) +#define OSTREE_IS_ASYNC_PROGRESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_ASYNC_PROGRESS)) +#define OSTREE_IS_ASYNC_PROGRESS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_ASYNC_PROGRESS)) +#define OSTREE_ASYNC_PROGRESS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_ASYNC_PROGRESS, OstreeAsyncProgressClass)) + +typedef struct OstreeAsyncProgress OstreeAsyncProgress; +typedef struct OstreeAsyncProgressClass OstreeAsyncProgressClass; + +struct OstreeAsyncProgressClass +{ + GObjectClass parent_class; + + void (*changed) (OstreeAsyncProgress *self, gpointer user_data); +}; + +_OSTREE_PUBLIC +GType ostree_async_progress_get_type (void) G_GNUC_CONST; + +_OSTREE_PUBLIC +OstreeAsyncProgress *ostree_async_progress_new (void); + +_OSTREE_PUBLIC +OstreeAsyncProgress *ostree_async_progress_new_and_connect (void (*changed) (OstreeAsyncProgress *self, gpointer user_data), gpointer user_data); + +_OSTREE_PUBLIC +char *ostree_async_progress_get_status (OstreeAsyncProgress *self); + +_OSTREE_PUBLIC +void ostree_async_progress_get (OstreeAsyncProgress *self, + ...) G_GNUC_NULL_TERMINATED; + +_OSTREE_PUBLIC +guint ostree_async_progress_get_uint (OstreeAsyncProgress *self, + const char *key); +_OSTREE_PUBLIC +guint64 ostree_async_progress_get_uint64 (OstreeAsyncProgress *self, + const char *key); +_OSTREE_PUBLIC +GVariant *ostree_async_progress_get_variant (OstreeAsyncProgress *self, + const char *key); + +_OSTREE_PUBLIC +void ostree_async_progress_set_status (OstreeAsyncProgress *self, + const char *status); + +_OSTREE_PUBLIC +void ostree_async_progress_set (OstreeAsyncProgress *self, + ...) G_GNUC_NULL_TERMINATED; + +_OSTREE_PUBLIC +void ostree_async_progress_set_uint (OstreeAsyncProgress *self, + const char *key, + guint value); +_OSTREE_PUBLIC +void ostree_async_progress_set_uint64 (OstreeAsyncProgress *self, + const char *key, + guint64 value); +_OSTREE_PUBLIC +void ostree_async_progress_set_variant (OstreeAsyncProgress *self, + const char *key, + GVariant *value); + +_OSTREE_PUBLIC +void ostree_async_progress_finish (OstreeAsyncProgress *self); + +_OSTREE_PUBLIC +void ostree_async_progress_copy_state (OstreeAsyncProgress *self, + OstreeAsyncProgress *dest); + +G_END_DECLS diff --git a/src/libostree/ostree-autocleanups.h b/src/libostree/ostree-autocleanups.h new file mode 100644 index 0000000..1401701 --- /dev/null +++ b/src/libostree/ostree-autocleanups.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Krzesimir Nowak + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +/* ostree can use g_autoptr backports from libglnx when glib is too + * old, but still avoid exposing them to users that also have an old + * glib */ +#if defined(OSTREE_COMPILATION) || GLIB_CHECK_VERSION(2, 44, 0) + +/* + * The following types have no specific clear/free/unref functions, so + * they can be used as the stack-allocated variables or as the + * g_autofree heap-allocated variables. + * + * OstreeRepoTransactionStats + * OstreeRepoImportArchiveOptions + * OstreeRepoExportArchiveOptions + * OstreeRepoCheckoutOptions + */ + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeDiffItem, ostree_diff_item_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoCommitModifier, ostree_repo_commit_modifier_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoDevInoCache, ostree_repo_devino_cache_unref) + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeAsyncProgress, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeBootconfigParser, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeCommitSizesEntry, ostree_commit_sizes_entry_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeDeployment, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeGpgVerifyResult, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeKernelArgs, ostree_kernel_args_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeMutableTree, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepo, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFile, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSePolicy, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSysroot, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSysrootUpgrader, g_object_unref) + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (OstreeRepoCommitTraverseIter, ostree_repo_commit_traverse_iter_clear) + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeCollectionRef, ostree_collection_ref_free) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC (OstreeCollectionRefv, ostree_collection_ref_freev, NULL) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRemote, ostree_remote_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinder, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderAvahi, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderConfig, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderMount, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderOverride, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoFinderResult, ostree_repo_finder_result_free) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC (OstreeRepoFinderResultv, ostree_repo_finder_result_freev, NULL) + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSign, g_object_unref) +#endif + +G_END_DECLS diff --git a/src/libostree/ostree-bloom-private.h b/src/libostree/ostree-bloom-private.h new file mode 100644 index 0000000..1c5acb8 --- /dev/null +++ b/src/libostree/ostree-bloom-private.h @@ -0,0 +1,107 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "libglnx.h" + +G_BEGIN_DECLS + +/** + * OstreeBloom: + * + * An implementation of a [bloom filter](https://en.wikipedia.org/wiki/Bloom_filter) + * which is suitable for building a filter and looking keys up in an existing + * filter. + * + * Since: 2017.8 + */ +typedef struct _OstreeBloom OstreeBloom; + +/** + * OstreeBloomHashFunc: + * @element: a pointer to the element to hash + * @k: hash function parameter + * + * Function prototype for a + * [universal hash function](https://en.wikipedia.org/wiki/Universal_hashing), + * parameterised on @k, which hashes @element to a #guint64 hash value. + * + * It is up to the implementer of the hash function whether %NULL is valid for + * @element. + * + * Since: 2017.8 + */ +typedef guint64 (*OstreeBloomHashFunc) (gconstpointer element, + guint8 k); + +#define OSTREE_TYPE_BLOOM (ostree_bloom_get_type ()) + +G_GNUC_INTERNAL +GType ostree_bloom_get_type (void); + +G_GNUC_INTERNAL +OstreeBloom *ostree_bloom_new (gsize n_bytes, + guint8 k, + OstreeBloomHashFunc hash_func); + +G_GNUC_INTERNAL +OstreeBloom *ostree_bloom_new_from_bytes (GBytes *bytes, + guint8 k, + OstreeBloomHashFunc hash_func); + +G_GNUC_INTERNAL +OstreeBloom *ostree_bloom_ref (OstreeBloom *bloom); +G_GNUC_INTERNAL +void ostree_bloom_unref (OstreeBloom *bloom); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeBloom, ostree_bloom_unref) + +G_GNUC_INTERNAL +gboolean ostree_bloom_maybe_contains (OstreeBloom *bloom, + gconstpointer element); + +G_GNUC_INTERNAL +GBytes *ostree_bloom_seal (OstreeBloom *bloom); + +G_GNUC_INTERNAL +void ostree_bloom_add_element (OstreeBloom *bloom, + gconstpointer element); + +G_GNUC_INTERNAL +gsize ostree_bloom_get_size (OstreeBloom *bloom); +G_GNUC_INTERNAL +guint8 ostree_bloom_get_k (OstreeBloom *bloom); +G_GNUC_INTERNAL +OstreeBloomHashFunc ostree_bloom_get_hash_func (OstreeBloom *bloom); + +G_GNUC_INTERNAL +guint64 ostree_str_bloom_hash (gconstpointer element, + guint8 k); + +G_END_DECLS diff --git a/src/libostree/ostree-bloom.c b/src/libostree/ostree-bloom.c new file mode 100644 index 0000000..94edac6 --- /dev/null +++ b/src/libostree/ostree-bloom.c @@ -0,0 +1,606 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "ostree-bloom-private.h" + +/** + * SECTION:bloom + * @title: Bloom filter + * @short_description: Bloom filter implementation supporting building and + * reading filters + * @stability: Unstable + * @include: libostree/ostree-bloom-private.h + * + * #OstreeBloom is an implementation of a bloom filter which supports writing to + * and loading from a #GBytes bit array. The caller must store metadata about + * the bloom filter (its hash function and `k` parameter value) separately, as + * the same values must be used when reading from a serialised bit array as were + * used to build the array in the first place. + * + * This is a standard implementation of a bloom filter, and background reading + * on the theory can be + * [found on Wikipedia](https://en.wikipedia.org/wiki/Bloom_filter). In + * particular, a bloom filter is parameterised by `m` and `k` parameters: the + * size of the bit array (in bits) is `m`, and the number of hash functions + * applied to each element is `k`. Bloom filters require a universal hash + * function which can be parameterised by `k`. We have #OstreeBloomHashFunc, + * with ostree_str_bloom_hash() being an implementation for strings. + * + * The serialised output from a bloom filter is guaranteed to be stable across + * versions of libostree as long as the same values for `k` and the hash + * function are used. + * + * #OstreeBloom is mutable when constructed with ostree_bloom_new(), and elements + * can be added to it using ostree_bloom_add_element(), until ostree_bloom_seal() + * is called to serialise it and make it immutable. After then, the bloom filter + * can only be queried using ostree_bloom_maybe_contains(). + * + * If constructed with ostree_bloom_new_from_bytes(), the bloom filter is + * immutable from construction, and can only be queried. + * + * Reference: + * - https://en.wikipedia.org/wiki/Bloom_filter + * - https://llimllib.github.io/bloomfilter-tutorial/ + * + * Since: 2017.8 + */ + +struct _OstreeBloom +{ + guint ref_count; + gsize n_bytes; /* 0 < n_bytes <= G_MAXSIZE / 8 */ + gboolean is_mutable; /* determines which of [im]mutable_bytes is accessed */ + union + { + guint8 *mutable_bytes; /* owned; mutually exclusive */ + GBytes *immutable_bytes; /* owned; mutually exclusive */ + }; + guint8 k; + OstreeBloomHashFunc hash_func; +}; + +G_DEFINE_BOXED_TYPE (OstreeBloom, ostree_bloom, ostree_bloom_ref, ostree_bloom_unref) + +/** + * ostree_bloom_new: + * @n_bytes: size to make the bloom filter, in bytes + * @k: number of hash functions to use + * @hash_func: universal hash function to use + * + * Create a new mutable #OstreeBloom filter, with all its bits initialised to + * zero. Set elements in the filter using ostree_bloom_add_element(), and seal + * it to return an immutable #GBytes using ostree_bloom_seal(). + * + * To load an #OstreeBloom from an existing #GBytes, use + * ostree_bloom_new_from_bytes(). + * + * Note that @n_bytes is in bytes, so is 8 times smaller than the parameter `m` + * which is used when describing bloom filters academically. + * + * Returns: (transfer full): a new mutable bloom filter + * + * Since: 2017.8 + */ +OstreeBloom * +ostree_bloom_new (gsize n_bytes, + guint8 k, + OstreeBloomHashFunc hash_func) +{ + g_autoptr(OstreeBloom) bloom = NULL; + + g_return_val_if_fail (n_bytes > 0, NULL); + g_return_val_if_fail (n_bytes <= G_MAXSIZE / 8, NULL); + g_return_val_if_fail (k > 0, NULL); + g_return_val_if_fail (hash_func != NULL, NULL); + + bloom = g_new0 (OstreeBloom, 1); + bloom->ref_count = 1; + + bloom->is_mutable = TRUE; + bloom->mutable_bytes = g_malloc0 (n_bytes); + bloom->n_bytes = n_bytes; + bloom->k = k; + bloom->hash_func = hash_func; + + return g_steal_pointer (&bloom); +} + +/** + * ostree_bloom_new_from_bytes: + * @bytes: array of bytes containing the filter data + * @k: number of hash functions to use + * @hash_func: universal hash function to use + * + * Load an immutable #OstreeBloom filter from the given @bytes. Check whether + * elements are probably set in the filter using ostree_bloom_maybe_contains(). + * + * To create a new mutable #OstreeBloom, use ostree_bloom_new(). + * + * Note that all the bits in @bytes are loaded, so the parameter `m` for the + * filter (as commonly used in academic literature) is always a multiple of 8. + * + * Returns: (transfer full): a new immutable bloom filter + * + * Since: 2017.8 + */ +OstreeBloom * +ostree_bloom_new_from_bytes (GBytes *bytes, + guint8 k, + OstreeBloomHashFunc hash_func) +{ + g_autoptr(OstreeBloom) bloom = NULL; + + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (g_bytes_get_size (bytes) > 0, NULL); + g_return_val_if_fail (g_bytes_get_size (bytes) <= G_MAXSIZE / 8, NULL); + g_return_val_if_fail (k > 0, NULL); + g_return_val_if_fail (hash_func != NULL, NULL); + + bloom = g_new0 (OstreeBloom, 1); + bloom->ref_count = 1; + + bloom->is_mutable = FALSE; + bloom->immutable_bytes = g_bytes_ref (bytes); + bloom->n_bytes = g_bytes_get_size (bytes); + bloom->k = k; + bloom->hash_func = hash_func; + + return g_steal_pointer (&bloom); +} + +/** + * ostree_bloom_ref: + * @bloom: an #OstreeBloom + * + * Increase the reference count of @bloom. + * + * Returns: (transfer full): @bloom + * Since: 2017.8 + */ +OstreeBloom * +ostree_bloom_ref (OstreeBloom *bloom) +{ + g_return_val_if_fail (bloom != NULL, NULL); + g_return_val_if_fail (bloom->ref_count >= 1, NULL); + g_return_val_if_fail (bloom->ref_count == G_MAXUINT - 1, NULL); + + bloom->ref_count++; + + return bloom; +} + +/** + * ostree_bloom_unref: + * @bloom: (transfer full): an #OstreeBloom + * + * Decrement the reference count of @bloom. If it reaches zero, the filter + * is destroyed. + * + * Since: 2017.8 + */ +void +ostree_bloom_unref (OstreeBloom *bloom) +{ + g_return_if_fail (bloom != NULL); + g_return_if_fail (bloom->ref_count >= 1); + + bloom->ref_count--; + + if (bloom->ref_count == 0) + { + if (bloom->is_mutable) + g_clear_pointer (&bloom->mutable_bytes, g_free); + else + g_clear_pointer (&bloom->immutable_bytes, g_bytes_unref); + bloom->n_bytes = 0; + g_free (bloom); + } +} + +/* @idx is in bits, not bytes. */ +static inline gboolean +ostree_bloom_get_bit (OstreeBloom *bloom, + gsize idx) +{ + const guint8 *bytes; + + if (bloom->is_mutable) + bytes = bloom->mutable_bytes; + else + bytes = g_bytes_get_data (bloom->immutable_bytes, NULL); + + g_assert (idx / 8 < bloom->n_bytes); + return (bytes[idx / 8] & (1 << (idx % 8))); +} + +/* @idx is in bits, not bytes. */ +static inline void +ostree_bloom_set_bit (OstreeBloom *bloom, + gsize idx) +{ + g_assert (bloom->is_mutable); + g_assert (idx / 8 < bloom->n_bytes); + bloom->mutable_bytes[idx / 8] |= (guint8) (1 << (idx % 8)); +} + +/** + * ostree_bloom_maybe_contains: + * @bloom: an #OstreeBloom + * @element: (nullable): element to check for membership + * + * Check whether @element is potentially in @bloom, or whether it definitely + * isn’t. @element may be %NULL only if the hash function passed to @bloom at + * construction time supports %NULL elements. + * + * Returns: %TRUE if @element is potentially in @bloom; %FALSE if it definitely + * isn’t + * Since: 2017.8 + */ +gboolean +ostree_bloom_maybe_contains (OstreeBloom *bloom, + gconstpointer element) +{ + guint8 i; + + g_return_val_if_fail (bloom != NULL, TRUE); + g_return_val_if_fail (bloom->ref_count >= 1, TRUE); + + for (i = 0; i < bloom->k; i++) + { + guint64 idx; + + idx = bloom->hash_func (element, i); + + if (!ostree_bloom_get_bit (bloom, (gsize) (idx % (bloom->n_bytes * 8)))) + return FALSE; /* definitely not in the set */ + } + + return TRUE; /* possibly in the set */ +} + +/** + * ostree_bloom_seal: + * @bloom: an #OstreeBloom + * + * Seal a constructed bloom filter, so that elements may no longer be added to + * it, and queries can now be performed against it. The serialised form of the + * bloom filter is returned as a bit array. Note that this does not include + * information about the filter hash function or parameters; the caller is + * responsible for serialising those separately if appropriate. + * + * It is safe to call this function multiple times. + * + * Returns: (transfer full): a #GBytes containing the immutable filter data + * Since: 2017.8 + */ +GBytes * +ostree_bloom_seal (OstreeBloom *bloom) +{ + g_return_val_if_fail (bloom != NULL, NULL); + g_return_val_if_fail (bloom->ref_count >= 1, NULL); + + if (bloom->is_mutable) + { + bloom->is_mutable = FALSE; + bloom->immutable_bytes = g_bytes_new_take (g_steal_pointer (&bloom->mutable_bytes), bloom->n_bytes); + } + + return g_bytes_ref (bloom->immutable_bytes); +} + +/** + * ostree_bloom_add_element: + * @bloom: an #OstreeBloom + * @element: (nullable): element to add to the filter + * + * Add the given @element to the bloom filter, which must not yet have been + * sealed (ostree_bloom_seal()). @element may be %NULL if the hash function + * passed to @bloom at construction time supports %NULL elements. + * + * Since: 2017.8 + */ +void +ostree_bloom_add_element (OstreeBloom *bloom, + gconstpointer element) +{ + guint8 i; + + g_return_if_fail (bloom != NULL); + g_return_if_fail (bloom->ref_count >= 1); + g_return_if_fail (bloom->is_mutable); + + for (i = 0; i < bloom->k; i++) + { + guint64 idx = bloom->hash_func (element, i); + ostree_bloom_set_bit (bloom, (gsize) (idx % (bloom->n_bytes * 8))); + } +} + +/** + * ostree_bloom_get_size: + * @bloom: an #OstreeBloom + * + * Get the size of the #OstreeBloom filter, in bytes, as configured at + * construction time. + * + * Returns: the bloom filter’s size in bytes, guaranteed to be >0 + * Since: 2017.8 + */ +gsize +ostree_bloom_get_size (OstreeBloom *bloom) +{ + g_return_val_if_fail (bloom != NULL, 0); + + return bloom->n_bytes; +} + +/** + * ostree_bloom_get_k: + * @bloom: an #OstreeBloom + * + * Get the `k` value from the #OstreeBloom filter, as configured at + * construction time. + * + * Returns: the bloom filter’s `k` value, guaranteed to be >0 + * Since: 2017.8 + */ +guint8 +ostree_bloom_get_k (OstreeBloom *bloom) +{ + g_return_val_if_fail (bloom != NULL, 0); + + return bloom->k; +} + +/** + * ostree_bloom_get_hash_func: + * @bloom: an #OstreeBloom + * + * Get the #OstreeBloomHashFunc from the #OstreeBloom filter, as configured at + * construction time. + * + * Returns: the bloom filter’s universal hash function + * Since: 2017.8 + */ +OstreeBloomHashFunc +ostree_bloom_get_hash_func (OstreeBloom *bloom) +{ + g_return_val_if_fail (bloom != NULL, NULL); + + return bloom->hash_func; +} + +/* SipHash code adapted from https://github.com/veorq/SipHash/blob/master/siphash.c */ + +/* + SipHash reference C implementation + Copyright (c) 2012-2016 Jean-Philippe Aumasson + + Copyright (c) 2012-2014 Daniel J. Bernstein + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . + */ + +/* default: SipHash-2-4 */ +#define cROUNDS 2 +#define dROUNDS 4 + +#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) + +#define U32TO8_LE(p, v) \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); + +#define U64TO8_LE(p, v) \ + U32TO8_LE((p), (uint32_t)((v))); \ + U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); + +#define U8TO64_LE(p) \ + (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ + ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ + ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ + ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) + +#define SIPROUND \ + do { \ + v0 += v1; \ + v1 = ROTL(v1, 13); \ + v1 ^= v0; \ + v0 = ROTL(v0, 32); \ + v2 += v3; \ + v3 = ROTL(v3, 16); \ + v3 ^= v2; \ + v0 += v3; \ + v3 = ROTL(v3, 21); \ + v3 ^= v0; \ + v2 += v1; \ + v1 = ROTL(v1, 17); \ + v1 ^= v2; \ + v2 = ROTL(v2, 32); \ + } while (0) + +#ifdef DEBUG +#define TRACE \ + do { \ + printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32), \ + (uint32_t)v0); \ + printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32), \ + (uint32_t)v1); \ + printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32), \ + (uint32_t)v2); \ + printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32), \ + (uint32_t)v3); \ + } while (0) +#else +#define TRACE +#endif + +static int siphash(const uint8_t *in, const size_t inlen, const uint8_t *k, + uint8_t *out, const size_t outlen) { + + assert((outlen == 8) || (outlen == 16)); + uint64_t v0 = 0x736f6d6570736575ULL; + uint64_t v1 = 0x646f72616e646f6dULL; + uint64_t v2 = 0x6c7967656e657261ULL; + uint64_t v3 = 0x7465646279746573ULL; + uint64_t k0 = U8TO64_LE(k); + uint64_t k1 = U8TO64_LE(k + 8); + uint64_t m; + int i; + const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); + const int left = inlen & 7; + uint64_t b = ((uint64_t)inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + if (outlen == 16) + v1 ^= 0xee; + + for (; in != end; in += 8) { + m = U8TO64_LE(in); + v3 ^= m; + + TRACE; + for (i = 0; i < cROUNDS; ++i) + SIPROUND; + + v0 ^= m; + } + + switch (left) { + case 7: + b |= ((uint64_t)in[6]) << 48; + case 6: + b |= ((uint64_t)in[5]) << 40; + case 5: + b |= ((uint64_t)in[4]) << 32; + case 4: + b |= ((uint64_t)in[3]) << 24; + case 3: + b |= ((uint64_t)in[2]) << 16; + case 2: + b |= ((uint64_t)in[1]) << 8; + case 1: + b |= ((uint64_t)in[0]); + break; + case 0: + break; + } + + v3 ^= b; + + TRACE; + for (i = 0; i < cROUNDS; ++i) + SIPROUND; + + v0 ^= b; + + if (outlen == 16) + v2 ^= 0xee; + else + v2 ^= 0xff; + + TRACE; + for (i = 0; i < dROUNDS; ++i) + SIPROUND; + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out, b); + + if (outlen == 8) + return 0; + + v1 ^= 0xdd; + + TRACE; + for (i = 0; i < dROUNDS; ++i) + SIPROUND; + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out + 8, b); + + return 0; +} + +/* End SipHash copied code. */ + +/** + * ostree_str_bloom_hash: + * @element: element to calculate the hash for + * @k: hash function index + * + * A universal hash function implementation for strings. It expects @element to + * be a pointer to a string (i.e. @element has type `const gchar*`), and expects + * @k to be in the range `[0, k_max)`, where `k_max` is the `k` value used to + * construct the bloom filter. The output range from this hash function could be + * any value in #guint64, and it handles input strings of any length. + * + * This function does not allow %NULL as a valid value for @element. + * + * Reference: + * - https://www.131002.net/siphash/ + * + * Returns: hash of the string at @element using parameter @k + * Since: 2017.8 + */ +guint64 +ostree_str_bloom_hash (gconstpointer element, + guint8 k) +{ + const gchar *str = element; + gsize str_len; + union + { + guint64 u64; + guint8 u8[8]; + } out_le; + guint8 k_array[16]; + gsize i; + + str_len = strlen (str); + for (i = 0; i < G_N_ELEMENTS (k_array); i++) + k_array[i] = k; + + siphash ((const guint8 *) str, str_len, k_array, out_le.u8, sizeof (out_le)); + + return le64toh (out_le.u64); +} diff --git a/src/libostree/ostree-bootconfig-parser.c b/src/libostree/ostree-bootconfig-parser.c new file mode 100644 index 0000000..67f9fb5 --- /dev/null +++ b/src/libostree/ostree-bootconfig-parser.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-bootconfig-parser.h" +#include "otutil.h" + +struct _OstreeBootconfigParser +{ + GObject parent_instance; + + gboolean parsed; + const char *separators; + + GHashTable *options; +}; + +typedef GObjectClass OstreeBootconfigParserClass; + +G_DEFINE_TYPE (OstreeBootconfigParser, ostree_bootconfig_parser, G_TYPE_OBJECT) + +/** + * ostree_bootconfig_parser_clone: + * @self: Bootconfig to clone + * + * Returns: (transfer full): Copy of @self + */ +OstreeBootconfigParser * +ostree_bootconfig_parser_clone (OstreeBootconfigParser *self) +{ + OstreeBootconfigParser *parser = ostree_bootconfig_parser_new (); + + GLNX_HASH_TABLE_FOREACH_KV (self->options, const char*, k, const char*, v) + g_hash_table_replace (parser->options, g_strdup (k), g_strdup (v)); + + return parser; +} + +/** + * ostree_bootconfig_parser_parse_at: + * @self: Parser + * @dfd: Directory fd + * @path: File path + * @cancellable: Cancellable + * @error: Error + * + * Initialize a bootconfig from the given file. + */ +gboolean +ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (!self->parsed, FALSE); + + g_autofree char *contents = glnx_file_get_contents_utf8_at (dfd, path, NULL, cancellable, error); + if (!contents) + return FALSE; + + g_auto(GStrv) lines = g_strsplit (contents, "\n", -1); + for (char **iter = lines; *iter; iter++) + { + const char *line = *iter; + + if (g_ascii_isalpha (*line)) + { + char **items = NULL; + items = g_strsplit_set (line, self->separators, 2); + if (g_strv_length (items) == 2 && items[0][0] != '\0') + { + g_hash_table_insert (self->options, items[0], items[1]); + g_free (items); /* Transfer ownership */ + } + else + { + g_strfreev (items); + } + } + } + + self->parsed = TRUE; + + return TRUE; +} + +gboolean +ostree_bootconfig_parser_parse (OstreeBootconfigParser *self, + GFile *path, + GCancellable *cancellable, + GError **error) +{ + return ostree_bootconfig_parser_parse_at (self, AT_FDCWD, gs_file_get_path_cached (path), + cancellable, error); +} + +void +ostree_bootconfig_parser_set (OstreeBootconfigParser *self, + const char *key, + const char *value) +{ + g_hash_table_replace (self->options, g_strdup (key), g_strdup (value)); +} + +const char * +ostree_bootconfig_parser_get (OstreeBootconfigParser *self, + const char *key) +{ + return g_hash_table_lookup (self->options, key); +} + +static void +write_key (OstreeBootconfigParser *self, + GString *buf, + const char *key, + const char *value) +{ + g_string_append (buf, key); + g_string_append_c (buf, self->separators[0]); + g_string_append (buf, value); + g_string_append_c (buf, '\n'); +} + +gboolean +ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + /* Write the fields in a deterministic order, following what is used + * in the bootconfig example of the BootLoaderspec document: + * https://systemd.io/BOOT_LOADER_SPECIFICATION + */ + const char *fields[] = { "title", "version", "options", "devicetree", "linux", "initrd" }; + g_autoptr(GHashTable) keys_written = g_hash_table_new (g_str_hash, g_str_equal); + g_autoptr(GString) buf = g_string_new (""); + + for (guint i = 0; i < G_N_ELEMENTS (fields); i++) + { + const char *key = fields[i]; + const char *value = g_hash_table_lookup (self->options, key); + if (value != NULL) + { + write_key (self, buf, key, value); + g_hash_table_add (keys_written, (gpointer)key); + } + } + + /* Write unknown fields */ + GLNX_HASH_TABLE_FOREACH_KV (self->options, const char*, k, const char*, v) + { + if (g_hash_table_lookup (keys_written, k)) + continue; + write_key (self, buf, k, v); + } + + if (!glnx_file_replace_contents_at (dfd, path, (guint8*)buf->str, buf->len, + GLNX_FILE_REPLACE_NODATASYNC, + cancellable, error)) + return FALSE; + + return TRUE; +} + +gboolean +ostree_bootconfig_parser_write (OstreeBootconfigParser *self, + GFile *output, + GCancellable *cancellable, + GError **error) +{ + return ostree_bootconfig_parser_write_at (self, + AT_FDCWD, gs_file_get_path_cached (output), + cancellable, error); +} + +static void +ostree_bootconfig_parser_finalize (GObject *object) +{ + OstreeBootconfigParser *self = OSTREE_BOOTCONFIG_PARSER (object); + + g_hash_table_unref (self->options); + + G_OBJECT_CLASS (ostree_bootconfig_parser_parent_class)->finalize (object); +} + +static void +ostree_bootconfig_parser_init (OstreeBootconfigParser *self) +{ + self->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); +} + +void +ostree_bootconfig_parser_class_init (OstreeBootconfigParserClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = ostree_bootconfig_parser_finalize; +} + +OstreeBootconfigParser * +ostree_bootconfig_parser_new (void) +{ + OstreeBootconfigParser *self = NULL; + + self = g_object_new (OSTREE_TYPE_BOOTCONFIG_PARSER, NULL); + self->separators = " \t"; + return self; +} diff --git a/src/libostree/ostree-bootconfig-parser.h b/src/libostree/ostree-bootconfig-parser.h new file mode 100644 index 0000000..aec0753 --- /dev/null +++ b/src/libostree/ostree-bootconfig-parser.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_BOOTCONFIG_PARSER (ostree_bootconfig_parser_get_type ()) +#define OSTREE_BOOTCONFIG_PARSER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_BOOTCONFIG_PARSER, OstreeBootconfigParser)) +#define OSTREE_IS_BOOTCONFIG_PARSER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_BOOTCONFIG_PARSER)) + +typedef struct _OstreeBootconfigParser OstreeBootconfigParser; + +_OSTREE_PUBLIC +GType ostree_bootconfig_parser_get_type (void) G_GNUC_CONST; + +_OSTREE_PUBLIC +OstreeBootconfigParser * ostree_bootconfig_parser_new (void); + +_OSTREE_PUBLIC +OstreeBootconfigParser * ostree_bootconfig_parser_clone (OstreeBootconfigParser *self); + +_OSTREE_PUBLIC +gboolean ostree_bootconfig_parser_parse (OstreeBootconfigParser *self, + GFile *path, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_bootconfig_parser_write (OstreeBootconfigParser *self, + GFile *output, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_bootconfig_parser_set (OstreeBootconfigParser *self, + const char *key, + const char *value); + +_OSTREE_PUBLIC +const char *ostree_bootconfig_parser_get (OstreeBootconfigParser *self, + const char *key); + + +G_END_DECLS diff --git a/src/libostree/ostree-bootloader-grub2.c b/src/libostree/ostree-bootloader-grub2.c new file mode 100644 index 0000000..ceea682 --- /dev/null +++ b/src/libostree/ostree-bootloader-grub2.c @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-sysroot-private.h" +#include "ostree-bootloader-grub2.h" +#include "otutil.h" +#include +#include +#include + +#include + +/* I only did some cursory research here, but it appears + * that we only want to use "linux16" for x86 platforms. + * At least, I got a report that "linux16" is definitely wrong + * for ppc64. See + * http://pkgs.fedoraproject.org/cgit/rpms/grub2.git/tree/0036-Use-linux16-when-appropriate-880840.patch?h=f25 + * https://bugzilla.redhat.com/show_bug.cgi?id=1108296 + * among others. + */ +#if defined(__i386__) || defined(__x86_64__) +#define GRUB2_SUFFIX "16" +#else +#define GRUB2_SUFFIX "" +#endif +/* https://github.com/projectatomic/rpm-ostree-toolbox/issues/102#issuecomment-316483554 + * https://github.com/rhboot/grubby/blob/34b1436ccbd56eab8024314cab48f2fc880eef08/grubby.c#L63 + * + * This is true at least on Fedora/Red Hat Enterprise Linux for aarch64. + */ +#if defined(__aarch64__) +#define GRUB2_EFI_SUFFIX "" +#else +#define GRUB2_EFI_SUFFIX "efi" +#endif + +struct _OstreeBootloaderGrub2 +{ + GObject parent_instance; + + OstreeSysroot *sysroot; + GFile *config_path_bios_1; + GFile *config_path_bios_2; + GFile *config_path_efi; + gboolean is_efi; +}; + +typedef GObjectClass OstreeBootloaderGrub2Class; + +static void _ostree_bootloader_grub2_bootloader_iface_init (OstreeBootloaderInterface *iface); +G_DEFINE_TYPE_WITH_CODE (OstreeBootloaderGrub2, _ostree_bootloader_grub2, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_BOOTLOADER, _ostree_bootloader_grub2_bootloader_iface_init)); + +static gboolean +_ostree_bootloader_grub2_query (OstreeBootloader *bootloader, + gboolean *out_is_active, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); + + /* Look for the BIOS path first */ + if (g_file_query_exists (self->config_path_bios_1, NULL) || + g_file_query_exists (self->config_path_bios_2, NULL)) + { + /* If we found it, we're done */ + *out_is_active = TRUE; + return TRUE; + } + + g_autoptr(GFile) efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI"); + + g_clear_object (&self->config_path_efi); + + if (g_file_query_exists (efi_basedir, NULL)) + { + g_autoptr(GFileEnumerator) direnum = NULL; + + direnum = g_file_enumerate_children (efi_basedir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!direnum) + return FALSE; + + while (TRUE) + { + GFileInfo *file_info; + const char *fname; + + if (!g_file_enumerator_iterate (direnum, &file_info, NULL, + cancellable, error)) + return FALSE; + if (file_info == NULL) + break; + + fname = g_file_info_get_name (file_info); + if (strcmp (fname, "BOOT") == 0) + continue; + + if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) + continue; + + g_autofree char *subdir_grub_cfg = + g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL); + + if (g_file_test (subdir_grub_cfg, G_FILE_TEST_EXISTS)) + { + self->config_path_efi = g_file_new_for_path (subdir_grub_cfg); + break; + } + } + + /* If we found the EFI path, we're done */ + if (self->config_path_efi) + { + self->is_efi = TRUE; + *out_is_active = TRUE; + return TRUE; + } + } + else + *out_is_active = FALSE; + + return TRUE; +} + +static const char * +_ostree_bootloader_grub2_get_name (OstreeBootloader *bootloader) +{ + return "grub2"; +} + +/* This implementation is quite complex; see this issue for + * a starting point: + * https://github.com/ostreedev/ostree/issues/717 + */ +gboolean +_ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot, + int bootversion, + int target_fd, + GCancellable *cancellable, + GError **error) +{ + /* So... yeah. Just going to hardcode these. */ + static const char hardcoded_video[] = "load_video\n" + "set gfxpayload=keep\n"; + static const char hardcoded_insmods[] = "insmod gzio\n"; + const char *grub2_boot_device_id = + g_getenv ("GRUB2_BOOT_DEVICE_ID"); + const char *grub2_prepare_root_cache = + g_getenv ("GRUB2_PREPARE_ROOT_CACHE"); + + /* We must have been called via the wrapper script */ + g_assert (grub2_boot_device_id != NULL); + g_assert (grub2_prepare_root_cache != NULL); + + /* Passed from the parent */ + gboolean is_efi = g_getenv ("_OSTREE_GRUB2_IS_EFI") != NULL; + + g_autoptr(GOutputStream) out_stream = g_unix_output_stream_new (target_fd, FALSE); + + g_autoptr(GPtrArray) loader_configs = NULL; + if (!_ostree_sysroot_read_boot_loader_configs (sysroot, bootversion, + &loader_configs, + cancellable, error)) + return FALSE; + + g_autoptr(GString) output = g_string_new (""); + for (guint i = 0; i < loader_configs->len; i++) + { + OstreeBootconfigParser *config = loader_configs->pdata[i]; + const char *title; + const char *options; + const char *kernel; + const char *initrd; + const char *devicetree; + char *quoted_title = NULL; + char *uuid = NULL; + char *quoted_uuid = NULL; + + title = ostree_bootconfig_parser_get (config, "title"); + if (!title) + title = "(Untitled)"; + + kernel = ostree_bootconfig_parser_get (config, "linux"); + + quoted_title = g_shell_quote (title); + uuid = g_strdup_printf ("ostree-%u-%s", (guint)i, grub2_boot_device_id); + quoted_uuid = g_shell_quote (uuid); + g_string_append_printf (output, "menuentry %s --class gnu-linux --class gnu --class os --unrestricted %s {\n", quoted_title, quoted_uuid); + g_free (uuid); + g_free (quoted_title); + g_free (quoted_uuid); + + /* Hardcoded sections */ + g_string_append (output, hardcoded_video); + g_string_append (output, hardcoded_insmods); + g_string_append (output, grub2_prepare_root_cache); + g_string_append_c (output, '\n'); + + if (!kernel) + return glnx_throw (error, "No \"linux\" key in bootloader config"); + g_string_append (output, "linux"); + if (is_efi) + g_string_append (output, GRUB2_EFI_SUFFIX); + else + g_string_append (output, GRUB2_SUFFIX); + g_string_append_c (output, ' '); + g_string_append (output, kernel); + + options = ostree_bootconfig_parser_get (config, "options"); + if (options) + { + g_string_append_c (output, ' '); + g_string_append (output, options); + } + g_string_append_c (output, '\n'); + + initrd = ostree_bootconfig_parser_get (config, "initrd"); + if (initrd) + { + g_string_append (output, "initrd"); + if (is_efi) + g_string_append (output, GRUB2_EFI_SUFFIX); + else + g_string_append (output, GRUB2_SUFFIX); + g_string_append_c (output, ' '); + g_string_append (output, initrd); + g_string_append_c (output, '\n'); + } + + devicetree = ostree_bootconfig_parser_get (config, "devicetree"); + if (devicetree) + { + g_string_append (output, "devicetree"); + g_string_append_c (output, ' '); + g_string_append (output, devicetree); + g_string_append_c (output, '\n'); + } + + g_string_append (output, "}\n"); + } + + gsize bytes_written; + if (!g_output_stream_write_all (out_stream, output->str, output->len, + &bytes_written, cancellable, error)) + return FALSE; + + return TRUE; +} + +typedef struct { + const char *root; + const char *bootversion_str; + gboolean is_efi; +} Grub2ChildSetupData; + +/* Post-fork, pre-exec child setup for grub2-mkconfig */ +static void +grub2_child_setup (gpointer user_data) +{ + Grub2ChildSetupData *cdata = user_data; + + setenv ("_OSTREE_GRUB2_BOOTVERSION", cdata->bootversion_str, TRUE); + /* We have to pass our state (whether or not we're using EFI) to the child */ + if (cdata->is_efi) + setenv ("_OSTREE_GRUB2_IS_EFI", "1", TRUE); + + /* Everything below this is dealing with the chroot case; if + * we're not doing that, return early. + */ + if (!cdata->root) + return; + + /* TODO: investigate replacing this with bwrap */ + if (chdir (cdata->root) != 0) + { + perror ("chdir"); + _exit (1); + } + + if (unshare (CLONE_NEWNS) != 0) + { + perror ("CLONE_NEWNS"); + _exit (1); + } + + if (mount (NULL, "/", "none", MS_REC|MS_PRIVATE, NULL) < 0) + { + perror ("Failed to make / a private mount"); + _exit (1); + } + + if (mount (".", ".", NULL, MS_BIND | MS_PRIVATE, NULL) < 0) + { + perror ("mount (MS_BIND)"); + _exit (1); + } + + if (mount (cdata->root, "/", NULL, MS_MOVE, NULL) < 0) + { + perror ("failed to MS_MOVE to /"); + _exit (1); + } + + if (chroot (".") != 0) + { + perror ("chroot"); + _exit (1); + } +} + +/* Main entrypoint for writing GRUB configuration. */ +static gboolean +_ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); + + /* Autotests can set this envvar to select which code path to test, useful for OS installers as well */ + gboolean use_system_grub2_mkconfig = TRUE; +#ifdef USE_BUILTIN_GRUB2_MKCONFIG + use_system_grub2_mkconfig = FALSE; +#endif + const gchar *grub_exec = g_getenv ("OSTREE_GRUB2_EXEC"); + if (grub_exec) + { + if (g_str_has_suffix (grub_exec, GRUB2_MKCONFIG_PATH)) + use_system_grub2_mkconfig = TRUE; + else + use_system_grub2_mkconfig = FALSE; + } + else + grub_exec = use_system_grub2_mkconfig ? GRUB2_MKCONFIG_PATH : TARGET_PREFIX "/lib/ostree/ostree-grub-generator"; + + g_autofree char *grub2_mkconfig_chroot = NULL; + if (use_system_grub2_mkconfig && ostree_sysroot_get_booted_deployment (self->sysroot) == NULL + && g_file_has_parent (self->sysroot->path, NULL)) + { + OstreeDeployment *tool_deployment; + g_autoptr(GFile) tool_deployment_root = NULL; + + g_assert_cmpint (new_deployments->len, >, 0); + tool_deployment = new_deployments->pdata[0]; + + /* Sadly we have to execute code to generate the bootloader configuration. + * If we're in a booted deployment, we just don't chroot. + * + * In the case of an installer, use the first deployment root (which + * will most likely be the only one. + * + * This all only applies if we're not using the builtin + * generator, which handles being run outside of the root. + */ + tool_deployment_root = ostree_sysroot_get_deployment_directory (self->sysroot, tool_deployment); + grub2_mkconfig_chroot = g_file_get_path (tool_deployment_root); + } + + g_debug ("Using grub2-mkconfig chroot: %s\n", grub2_mkconfig_chroot); + + g_autoptr(GFile) new_config_path = NULL; + g_autoptr(GFile) config_path_efi_dir = NULL; + if (self->is_efi) + { + config_path_efi_dir = g_file_get_parent (self->config_path_efi); + new_config_path = g_file_get_child (config_path_efi_dir, "grub.cfg.new"); + /* We use grub2-mkconfig to write to a temporary file first */ + if (!ot_gfile_ensure_unlinked (new_config_path, cancellable, error)) + return FALSE; + } + else + { + new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/grub.cfg", + bootversion); + } + + const char *grub_argv[4] = { NULL, "-o", NULL, NULL}; + Grub2ChildSetupData cdata = { NULL, }; + grub_argv[0] = grub_exec; + grub_argv[2] = gs_file_get_path_cached (new_config_path); + + GSpawnFlags grub_spawnflags = G_SPAWN_SEARCH_PATH; + if (!g_getenv ("OSTREE_DEBUG_GRUB2")) + grub_spawnflags |= G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL; + cdata.root = grub2_mkconfig_chroot; + g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion); + cdata.bootversion_str = bootversion_str; + cdata.is_efi = self->is_efi; + /* Note in older versions of the grub2 package, this script doesn't even try + to be atomic; it just does: + + cat ${grub_cfg}.new > ${grub_cfg} + rm -f ${grub_cfg}.new + + Upstream is fixed though. + */ + int grub2_estatus; + if (!g_spawn_sync (NULL, (char**)grub_argv, NULL, grub_spawnflags, + grub2_child_setup, &cdata, NULL, NULL, + &grub2_estatus, error)) + return FALSE; + if (!g_spawn_check_exit_status (grub2_estatus, error)) + { + g_prefix_error (error, "%s: ", grub_argv[0]); + return FALSE; + } + + /* Now let's fdatasync() for the new file */ + { glnx_autofd int new_config_fd = -1; + if (!glnx_openat_rdonly (AT_FDCWD, gs_file_get_path_cached (new_config_path), TRUE, &new_config_fd, error)) + return FALSE; + + if (fdatasync (new_config_fd) < 0) + return glnx_throw_errno_prefix (error, "fdatasync"); + } + + if (self->is_efi) + { + g_autoptr(GFile) config_path_efi_old = g_file_get_child (config_path_efi_dir, "grub.cfg.old"); + + /* copy current to old */ + if (!ot_gfile_ensure_unlinked (config_path_efi_old, cancellable, error)) + return FALSE; + if (!g_file_copy (self->config_path_efi, config_path_efi_old, + G_FILE_COPY_OVERWRITE, cancellable, NULL, NULL, error)) + return FALSE; + + /* NOTE: NON-ATOMIC REPLACEMENT; WE can't do anything else on FAT; + * see https://bugzilla.gnome.org/show_bug.cgi?id=724246 + */ + if (!ot_gfile_ensure_unlinked (self->config_path_efi, cancellable, error)) + return FALSE; + if (rename (gs_file_get_path_cached (new_config_path), gs_file_get_path_cached (self->config_path_efi)) < 0) + return glnx_throw_errno_prefix (error, "rename"); + } + + return TRUE; +} + +static gboolean +_ostree_bootloader_grub2_is_atomic (OstreeBootloader *bootloader) +{ + OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); + return !self->is_efi; +} + +static void +_ostree_bootloader_grub2_finalize (GObject *object) +{ + OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (object); + + g_clear_object (&self->sysroot); + g_clear_object (&self->config_path_bios_1); + g_clear_object (&self->config_path_bios_2); + g_clear_object (&self->config_path_efi); + + G_OBJECT_CLASS (_ostree_bootloader_grub2_parent_class)->finalize (object); +} + +void +_ostree_bootloader_grub2_init (OstreeBootloaderGrub2 *self) +{ +} + +static void +_ostree_bootloader_grub2_bootloader_iface_init (OstreeBootloaderInterface *iface) +{ + iface->query = _ostree_bootloader_grub2_query; + iface->get_name = _ostree_bootloader_grub2_get_name; + iface->write_config = _ostree_bootloader_grub2_write_config; + iface->is_atomic = _ostree_bootloader_grub2_is_atomic; +} + +void +_ostree_bootloader_grub2_class_init (OstreeBootloaderGrub2Class *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = _ostree_bootloader_grub2_finalize; +} + +OstreeBootloaderGrub2 * +_ostree_bootloader_grub2_new (OstreeSysroot *sysroot) +{ + OstreeBootloaderGrub2 *self = g_object_new (OSTREE_TYPE_BOOTLOADER_GRUB2, NULL); + self->sysroot = g_object_ref (sysroot); + /* Used by (at least) Debian */ + self->config_path_bios_1 = g_file_resolve_relative_path (self->sysroot->path, "boot/grub/grub.cfg"); + /* Used by (at least) Fedora */ + self->config_path_bios_2 = g_file_resolve_relative_path (self->sysroot->path, "boot/grub2/grub.cfg"); + return self; +} diff --git a/src/libostree/ostree-bootloader-grub2.h b/src/libostree/ostree-bootloader-grub2.h new file mode 100644 index 0000000..7aaa169 --- /dev/null +++ b/src/libostree/ostree-bootloader-grub2.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-bootloader.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_BOOTLOADER_GRUB2 (_ostree_bootloader_grub2_get_type ()) +#define OSTREE_BOOTLOADER_GRUB2(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_BOOTLOADER_GRUB2, OstreeBootloaderGrub2)) +#define OSTREE_IS_BOOTLOADER_GRUB2(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_BOOTLOADER_GRUB2)) + +typedef struct _OstreeBootloaderGrub2 OstreeBootloaderGrub2; + +GType _ostree_bootloader_grub2_get_type (void) G_GNUC_CONST; + +OstreeBootloaderGrub2 * _ostree_bootloader_grub2_new (OstreeSysroot *sysroot); + +gboolean _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-bootloader-syslinux.c b/src/libostree/ostree-bootloader-syslinux.c new file mode 100644 index 0000000..5fb8a1d --- /dev/null +++ b/src/libostree/ostree-bootloader-syslinux.c @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-sysroot-private.h" +#include "ostree-bootloader-syslinux.h" +#include "otutil.h" + +#include + +static const char syslinux_config_path[] = "boot/syslinux/syslinux.cfg"; + +struct _OstreeBootloaderSyslinux +{ + GObject parent_instance; + + OstreeSysroot *sysroot; +}; + +typedef GObjectClass OstreeBootloaderSyslinuxClass; + +static void _ostree_bootloader_syslinux_bootloader_iface_init (OstreeBootloaderInterface *iface); +G_DEFINE_TYPE_WITH_CODE (OstreeBootloaderSyslinux, _ostree_bootloader_syslinux, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_BOOTLOADER, _ostree_bootloader_syslinux_bootloader_iface_init)); + +static gboolean +_ostree_bootloader_syslinux_query (OstreeBootloader *bootloader, + gboolean *out_is_active, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader); + struct stat stbuf; + + if (!glnx_fstatat_allow_noent (self->sysroot->sysroot_fd, syslinux_config_path, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + *out_is_active = (errno == 0); + return TRUE; +} + +static const char * +_ostree_bootloader_syslinux_get_name (OstreeBootloader *bootloader) +{ + return "syslinux"; +} + +static gboolean +append_config_from_loader_entries (OstreeBootloaderSyslinux *self, + gboolean regenerate_default, + int bootversion, + GPtrArray *new_lines, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GPtrArray) loader_configs = NULL; + if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &loader_configs, + cancellable, error)) + return FALSE; + + for (guint i = 0; i < loader_configs->len; i++) + { + OstreeBootconfigParser *config = loader_configs->pdata[i]; + const char *val = ostree_bootconfig_parser_get (config, "title"); + if (!val) + val = "(Untitled)"; + + if (regenerate_default && i == 0) + g_ptr_array_add (new_lines, g_strdup_printf ("DEFAULT %s", val)); + + g_ptr_array_add (new_lines, g_strdup_printf ("LABEL %s", val)); + + val = ostree_bootconfig_parser_get (config, "linux"); + if (!val) + return glnx_throw (error, "No \"linux\" key in bootloader config"); + g_ptr_array_add (new_lines, g_strdup_printf ("\tKERNEL %s", val)); + + val = ostree_bootconfig_parser_get (config, "initrd"); + if (val) + g_ptr_array_add (new_lines, g_strdup_printf ("\tINITRD %s", val)); + + val = ostree_bootconfig_parser_get (config, "devicetree"); + if (val) + g_ptr_array_add (new_lines, g_strdup_printf ("\tDEVICETREE %s", val)); + + val = ostree_bootconfig_parser_get (config, "options"); + if (val) + g_ptr_array_add (new_lines, g_strdup_printf ("\tAPPEND %s", val)); + } + + return TRUE; +} + +static gboolean +_ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader); + + g_autofree char *new_config_path = + g_strdup_printf ("boot/loader.%d/syslinux.cfg", bootversion); + + /* This should follow the symbolic link to the current bootversion. */ + g_autofree char *config_contents = + glnx_file_get_contents_utf8_at (self->sysroot->sysroot_fd, syslinux_config_path, NULL, + cancellable, error); + if (!config_contents) + return FALSE; + + g_auto(GStrv) lines = g_strsplit (config_contents, "\n", -1); + g_autoptr(GPtrArray) new_lines = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GPtrArray) tmp_lines = g_ptr_array_new_with_free_func (g_free); + + g_autofree char *kernel_arg = NULL; + gboolean saw_default = FALSE; + gboolean regenerate_default = FALSE; + gboolean parsing_label = FALSE; + /* Note special iteration condition here; we want to also loop one + * more time at the end where line = NULL to ensure we finish off + * processing the last LABEL. + */ + for (char **iter = lines; iter; iter++) + { + const char *line = *iter; + gboolean skip = FALSE; + + if (parsing_label && + (line == NULL || !g_str_has_prefix (line, "\t"))) + { + parsing_label = FALSE; + if (kernel_arg == NULL) + return glnx_throw (error, "No KERNEL argument found after LABEL"); + + /* If this is a non-ostree kernel, just emit the lines + * we saw. + */ + if (!g_str_has_prefix (kernel_arg, "/ostree/")) + { + for (guint i = 0; i < tmp_lines->len; i++) + { + g_ptr_array_add (new_lines, tmp_lines->pdata[i]); + tmp_lines->pdata[i] = NULL; /* Transfer ownership */ + } + } + else + { + /* Otherwise, we drop the config on the floor - it + * will be regenerated. + */ + g_ptr_array_set_size (tmp_lines, 0); + } + } + + if (line == NULL) + break; + + if (!parsing_label && + (g_str_has_prefix (line, "LABEL "))) + { + parsing_label = TRUE; + g_ptr_array_set_size (tmp_lines, 0); + } + else if (parsing_label && g_str_has_prefix (line, "\tKERNEL ")) + { + g_free (kernel_arg); + kernel_arg = g_strdup (line + strlen ("\tKERNEL ")); + } + else if (!parsing_label && + (g_str_has_prefix (line, "DEFAULT "))) + { + saw_default = TRUE; + /* XXX Searching for patterns in the title is rather brittle, + * but this hack is at least noted in the code that builds + * the title to hopefully avoid regressions. */ + if (g_str_has_prefix (line, "DEFAULT ostree:") || /* old format */ + strstr (line, "(ostree") != NULL) /* new format */ + regenerate_default = TRUE; + skip = TRUE; + } + + if (!skip) + { + if (parsing_label) + g_ptr_array_add (tmp_lines, g_strdup (line)); + else + g_ptr_array_add (new_lines, g_strdup (line)); + } + } + + if (!saw_default) + regenerate_default = TRUE; + + if (!append_config_from_loader_entries (self, regenerate_default, + bootversion, new_lines, + cancellable, error)) + return FALSE; + + g_autofree char *new_config_contents = _ostree_sysroot_join_lines (new_lines); + if (!glnx_file_replace_contents_at (self->sysroot->sysroot_fd, new_config_path, + (guint8*)new_config_contents, strlen (new_config_contents), + GLNX_FILE_REPLACE_DATASYNC_NEW, + cancellable, error)) + return FALSE; + + return TRUE; +} + +static void +_ostree_bootloader_syslinux_finalize (GObject *object) +{ + OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (object); + + g_clear_object (&self->sysroot); + + G_OBJECT_CLASS (_ostree_bootloader_syslinux_parent_class)->finalize (object); +} + +void +_ostree_bootloader_syslinux_init (OstreeBootloaderSyslinux *self) +{ +} + +static void +_ostree_bootloader_syslinux_bootloader_iface_init (OstreeBootloaderInterface *iface) +{ + iface->query = _ostree_bootloader_syslinux_query; + iface->get_name = _ostree_bootloader_syslinux_get_name; + iface->write_config = _ostree_bootloader_syslinux_write_config; +} + +void +_ostree_bootloader_syslinux_class_init (OstreeBootloaderSyslinuxClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = _ostree_bootloader_syslinux_finalize; +} + +OstreeBootloaderSyslinux * +_ostree_bootloader_syslinux_new (OstreeSysroot *sysroot) +{ + OstreeBootloaderSyslinux *self = g_object_new (OSTREE_TYPE_BOOTLOADER_SYSLINUX, NULL); + self->sysroot = g_object_ref (sysroot); + return self; +} diff --git a/src/libostree/ostree-bootloader-syslinux.h b/src/libostree/ostree-bootloader-syslinux.h new file mode 100644 index 0000000..df4a939 --- /dev/null +++ b/src/libostree/ostree-bootloader-syslinux.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-bootloader.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_BOOTLOADER_SYSLINUX (_ostree_bootloader_syslinux_get_type ()) +#define OSTREE_BOOTLOADER_SYSLINUX(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_BOOTLOADER_SYSLINUX, OstreeBootloaderSyslinux)) +#define OSTREE_IS_BOOTLOADER_SYSLINUX(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_BOOTLOADER_SYSLINUX)) + +typedef struct _OstreeBootloaderSyslinux OstreeBootloaderSyslinux; + +GType _ostree_bootloader_syslinux_get_type (void) G_GNUC_CONST; + +OstreeBootloaderSyslinux * _ostree_bootloader_syslinux_new (OstreeSysroot *sysroot); + +G_END_DECLS diff --git a/src/libostree/ostree-bootloader-uboot.c b/src/libostree/ostree-bootloader-uboot.c new file mode 100644 index 0000000..1e1f037 --- /dev/null +++ b/src/libostree/ostree-bootloader-uboot.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2013 Collabora Ltd + * + * Based on ot-bootloader-syslinux.c by Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Javier Martinez Canillas + */ + +#include "config.h" + +#include "ostree-sysroot-private.h" +#include "ostree-bootloader-uboot.h" +#include "otutil.h" + +#include + +static const char uboot_config_path[] = "boot/loader/uEnv.txt"; + +struct _OstreeBootloaderUboot +{ + GObject parent_instance; + + OstreeSysroot *sysroot; +}; + +typedef GObjectClass OstreeBootloaderUbootClass; + +static void _ostree_bootloader_uboot_bootloader_iface_init (OstreeBootloaderInterface *iface); +G_DEFINE_TYPE_WITH_CODE (OstreeBootloaderUboot, _ostree_bootloader_uboot, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_BOOTLOADER, _ostree_bootloader_uboot_bootloader_iface_init)); + +static gboolean +_ostree_bootloader_uboot_query (OstreeBootloader *bootloader, + gboolean *out_is_active, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader); + struct stat stbuf; + + if (!glnx_fstatat_allow_noent (self->sysroot->sysroot_fd, uboot_config_path, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + *out_is_active = (errno == 0); + return TRUE; +} + +static const char * +_ostree_bootloader_uboot_get_name (OstreeBootloader *bootloader) +{ + return "U-Boot"; +} + +/* Append system's uEnv.txt, if it exists in $deployment/usr/lib/ostree-boot/ */ +static gboolean +append_system_uenv (OstreeBootloaderUboot *self, + const char *bootargs, + GPtrArray *new_lines, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int uenv_fd = -1; + g_autoptr(OstreeKernelArgs) kargs = NULL; + const char *uenv_path = NULL; + const char *ostree_arg = NULL; + + kargs = ostree_kernel_args_from_string (bootargs); + ostree_arg = ostree_kernel_args_get_last_value (kargs, "ostree"); + if (!ostree_arg) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No ostree= kernel argument found in boot loader configuration file"); + return FALSE; + } + ostree_arg += 1; + uenv_path = glnx_strjoina (ostree_arg, "/usr/lib/ostree-boot/uEnv.txt"); + if (!ot_openat_ignore_enoent (self->sysroot->sysroot_fd, uenv_path, &uenv_fd, error)) + return FALSE; + if (uenv_fd != -1) + { + char *uenv = glnx_fd_readall_utf8 (uenv_fd, NULL, cancellable, error); + if (!uenv) + { + g_prefix_error (error, "Reading %s: ", uenv_path); + return FALSE; + } + g_ptr_array_add (new_lines, uenv); + } + return TRUE; +} + +static gboolean +create_config_from_boot_loader_entries (OstreeBootloaderUboot *self, + int bootversion, + GPtrArray *new_lines, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GPtrArray) boot_loader_configs = NULL; + OstreeBootconfigParser *config; + const char *val; + + if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &boot_loader_configs, + cancellable, error)) + return FALSE; + + for (int i = 0; i < boot_loader_configs->len; i++) + { + g_autofree char *index_suffix = NULL; + if (i == 0) + index_suffix = g_strdup (""); + else + index_suffix = g_strdup_printf ("%d", i+1); + config = boot_loader_configs->pdata[i]; + + val = ostree_bootconfig_parser_get (config, "linux"); + if (!val) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No \"linux\" key in bootloader config"); + return FALSE; + } + g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image%s=%s", index_suffix, val)); + + val = ostree_bootconfig_parser_get (config, "initrd"); + if (val) + g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image%s=%s", index_suffix, val)); + + val = ostree_bootconfig_parser_get (config, "devicetree"); + if (val) + g_ptr_array_add (new_lines, g_strdup_printf ("fdt_file%s=%s", index_suffix, val)); + + val = ostree_bootconfig_parser_get (config, "fdtdir"); + if (val) + g_ptr_array_add (new_lines, g_strdup_printf ("fdtdir%s=%s", index_suffix, val)); + + val = ostree_bootconfig_parser_get (config, "options"); + if (val) + { + g_ptr_array_add (new_lines, g_strdup_printf ("bootargs%s=%s", index_suffix, val)); + if (i == 0) + if (!append_system_uenv (self, val, new_lines, cancellable, error)) + return FALSE; + } + } + + return TRUE; +} + +static gboolean +_ostree_bootloader_uboot_write_config (OstreeBootloader *bootloader, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (bootloader); + + /* This should follow the symbolic link to the current bootversion. */ + g_autofree char *config_contents = + glnx_file_get_contents_utf8_at (self->sysroot->sysroot_fd, uboot_config_path, NULL, + cancellable, error); + if (!config_contents) + return FALSE; + + g_autoptr(GPtrArray) new_lines = g_ptr_array_new_with_free_func (g_free); + if (!create_config_from_boot_loader_entries (self, bootversion, new_lines, + cancellable, error)) + return FALSE; + + g_autofree char *new_config_path = g_strdup_printf ("boot/loader.%d/uEnv.txt", bootversion); + g_autofree char *new_config_contents = _ostree_sysroot_join_lines (new_lines); + if (!glnx_file_replace_contents_at (self->sysroot->sysroot_fd, new_config_path, + (guint8*)new_config_contents, strlen (new_config_contents), + GLNX_FILE_REPLACE_DATASYNC_NEW, + cancellable, error)) + return FALSE; + + return TRUE; +} + +static void +_ostree_bootloader_uboot_finalize (GObject *object) +{ + OstreeBootloaderUboot *self = OSTREE_BOOTLOADER_UBOOT (object); + + g_clear_object (&self->sysroot); + + G_OBJECT_CLASS (_ostree_bootloader_uboot_parent_class)->finalize (object); +} + +void +_ostree_bootloader_uboot_init (OstreeBootloaderUboot *self) +{ +} + +static void +_ostree_bootloader_uboot_bootloader_iface_init (OstreeBootloaderInterface *iface) +{ + iface->query = _ostree_bootloader_uboot_query; + iface->get_name = _ostree_bootloader_uboot_get_name; + iface->write_config = _ostree_bootloader_uboot_write_config; +} + +void +_ostree_bootloader_uboot_class_init (OstreeBootloaderUbootClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = _ostree_bootloader_uboot_finalize; +} + +OstreeBootloaderUboot * +_ostree_bootloader_uboot_new (OstreeSysroot *sysroot) +{ + OstreeBootloaderUboot *self = g_object_new (OSTREE_TYPE_BOOTLOADER_UBOOT, NULL); + self->sysroot = g_object_ref (sysroot); + return self; +} diff --git a/src/libostree/ostree-bootloader-uboot.h b/src/libostree/ostree-bootloader-uboot.h new file mode 100644 index 0000000..89d7b47 --- /dev/null +++ b/src/libostree/ostree-bootloader-uboot.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2013 Collabora Ltd + * + * Based on ot-bootloader-syslinux.h by Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Javier Martinez Canillas + */ + +#pragma once + +#include "ostree-bootloader.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_BOOTLOADER_UBOOT (_ostree_bootloader_uboot_get_type ()) +#define OSTREE_BOOTLOADER_UBOOT(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_BOOTLOADER_UBOOT, OstreeBootloaderUboot)) +#define OSTREE_IS_BOOTLOADER_UBOOT(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_BOOTLOADER_UBOOT)) + +typedef struct _OstreeBootloaderUboot OstreeBootloaderUboot; + +GType _ostree_bootloader_uboot_get_type (void) G_GNUC_CONST; + +OstreeBootloaderUboot * _ostree_bootloader_uboot_new (OstreeSysroot *sysroot); + +G_END_DECLS diff --git a/src/libostree/ostree-bootloader-zipl.c b/src/libostree/ostree-bootloader-zipl.c new file mode 100644 index 0000000..4ac785d --- /dev/null +++ b/src/libostree/ostree-bootloader-zipl.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2019 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-sysroot-private.h" +#include "ostree-bootloader-zipl.h" +#include "otutil.h" + +#include + +/* This is specific to zipl today, but in the future we could also + * use it for the grub2-mkconfig case. + */ +static const char zipl_requires_execute_path[] = "boot/ostree-bootloader-update.stamp"; + +struct _OstreeBootloaderZipl +{ + GObject parent_instance; + + OstreeSysroot *sysroot; +}; + +typedef GObjectClass OstreeBootloaderZiplClass; + +static void _ostree_bootloader_zipl_bootloader_iface_init (OstreeBootloaderInterface *iface); +G_DEFINE_TYPE_WITH_CODE (OstreeBootloaderZipl, _ostree_bootloader_zipl, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_BOOTLOADER, _ostree_bootloader_zipl_bootloader_iface_init)); + +static gboolean +_ostree_bootloader_zipl_query (OstreeBootloader *bootloader, + gboolean *out_is_active, + GCancellable *cancellable, + GError **error) +{ + /* We don't auto-detect this one; should be explicitly chosen right now. + * see also https://github.com/coreos/coreos-assembler/pull/849 + */ + *out_is_active = FALSE; + return TRUE; +} + +static const char * +_ostree_bootloader_zipl_get_name (OstreeBootloader *bootloader) +{ + return "zipl"; +} + +static gboolean +_ostree_bootloader_zipl_write_config (OstreeBootloader *bootloader, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderZipl *self = OSTREE_BOOTLOADER_ZIPL (bootloader); + + /* Write our stamp file */ + if (!glnx_file_replace_contents_at (self->sysroot->sysroot_fd, zipl_requires_execute_path, + (guint8*)"", 0, GLNX_FILE_REPLACE_NODATASYNC, + cancellable, error)) + return FALSE; + + return TRUE; +} + +static gboolean +_ostree_bootloader_zipl_post_bls_sync (OstreeBootloader *bootloader, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderZipl *self = OSTREE_BOOTLOADER_ZIPL (bootloader); + + /* Note that unlike the grub2-mkconfig backend, we make no attempt to + * chroot(). + */ + g_assert (self->sysroot->booted_deployment); + + if (!glnx_fstatat_allow_noent (self->sysroot->sysroot_fd, zipl_requires_execute_path, NULL, 0, error)) + return FALSE; + + /* If there's no stamp file, nothing to do */ + if (errno == ENOENT) + return TRUE; + + const char *const zipl_argv[] = {"zipl", NULL}; + int estatus; + if (!g_spawn_sync (NULL, (char**)zipl_argv, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, NULL, &estatus, error)) + return FALSE; + if (!g_spawn_check_exit_status (estatus, error)) + return FALSE; + if (!glnx_unlinkat (self->sysroot->sysroot_fd, zipl_requires_execute_path, 0, error)) + return FALSE; + return TRUE; +} + +static void +_ostree_bootloader_zipl_finalize (GObject *object) +{ + OstreeBootloaderZipl *self = OSTREE_BOOTLOADER_ZIPL (object); + + g_clear_object (&self->sysroot); + + G_OBJECT_CLASS (_ostree_bootloader_zipl_parent_class)->finalize (object); +} + +void +_ostree_bootloader_zipl_init (OstreeBootloaderZipl *self) +{ +} + +static void +_ostree_bootloader_zipl_bootloader_iface_init (OstreeBootloaderInterface *iface) +{ + iface->query = _ostree_bootloader_zipl_query; + iface->get_name = _ostree_bootloader_zipl_get_name; + iface->write_config = _ostree_bootloader_zipl_write_config; + iface->post_bls_sync = _ostree_bootloader_zipl_post_bls_sync; +} + +void +_ostree_bootloader_zipl_class_init (OstreeBootloaderZiplClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = _ostree_bootloader_zipl_finalize; +} + +OstreeBootloaderZipl * +_ostree_bootloader_zipl_new (OstreeSysroot *sysroot) +{ + OstreeBootloaderZipl *self = g_object_new (OSTREE_TYPE_BOOTLOADER_ZIPL, NULL); + self->sysroot = g_object_ref (sysroot); + return self; +} diff --git a/src/libostree/ostree-bootloader-zipl.h b/src/libostree/ostree-bootloader-zipl.h new file mode 100644 index 0000000..79e8491 --- /dev/null +++ b/src/libostree/ostree-bootloader-zipl.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-bootloader.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_BOOTLOADER_ZIPL (_ostree_bootloader_zipl_get_type ()) +#define OSTREE_BOOTLOADER_ZIPL(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_BOOTLOADER_ZIPL, OstreeBootloaderZipl)) +#define OSTREE_IS_BOOTLOADER_ZIPL(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_BOOTLOADER_ZIPL)) + +typedef struct _OstreeBootloaderZipl OstreeBootloaderZipl; + +GType _ostree_bootloader_zipl_get_type (void) G_GNUC_CONST; + +OstreeBootloaderZipl * _ostree_bootloader_zipl_new (OstreeSysroot *sysroot); + +G_END_DECLS diff --git a/src/libostree/ostree-bootloader.c b/src/libostree/ostree-bootloader.c new file mode 100644 index 0000000..76b7bb8 --- /dev/null +++ b/src/libostree/ostree-bootloader.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "ostree-bootloader.h" + +G_DEFINE_INTERFACE (OstreeBootloader, _ostree_bootloader, G_TYPE_OBJECT) + +static void +_ostree_bootloader_default_init (OstreeBootloaderInterface *iface) +{ +} + +gboolean +_ostree_bootloader_query (OstreeBootloader *self, + gboolean *out_is_active, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_BOOTLOADER (self), FALSE); + + return OSTREE_BOOTLOADER_GET_IFACE (self)->query (self, out_is_active, cancellable, error); +} + +/** + * _ostree_bootloader_get_name: + * + * Returns: (transfer none): Name of this bootloader + */ +const char * +_ostree_bootloader_get_name (OstreeBootloader *self) +{ + g_return_val_if_fail (OSTREE_IS_BOOTLOADER (self), NULL); + + return OSTREE_BOOTLOADER_GET_IFACE (self)->get_name (self); +} + +gboolean +_ostree_bootloader_write_config (OstreeBootloader *self, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_BOOTLOADER (self), FALSE); + + return OSTREE_BOOTLOADER_GET_IFACE (self)->write_config (self, bootversion, + new_deployments, + cancellable, error); +} + +gboolean +_ostree_bootloader_post_bls_sync (OstreeBootloader *self, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_BOOTLOADER (self), FALSE); + + if (OSTREE_BOOTLOADER_GET_IFACE (self)->post_bls_sync) + return OSTREE_BOOTLOADER_GET_IFACE (self)->post_bls_sync (self, cancellable, error); + + return TRUE; +} + +gboolean +_ostree_bootloader_is_atomic (OstreeBootloader *self) +{ + g_return_val_if_fail (OSTREE_IS_BOOTLOADER (self), FALSE); + + if (OSTREE_BOOTLOADER_GET_IFACE (self)->is_atomic) + return OSTREE_BOOTLOADER_GET_IFACE (self)->is_atomic (self); + else + return TRUE; +} diff --git a/src/libostree/ostree-bootloader.h b/src/libostree/ostree-bootloader.h new file mode 100644 index 0000000..48a7a9c --- /dev/null +++ b/src/libostree/ostree-bootloader.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include "otutil.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_BOOTLOADER (_ostree_bootloader_get_type ()) +#define OSTREE_BOOTLOADER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_BOOTLOADER, OstreeBootloader)) +#define OSTREE_IS_BOOTLOADER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_BOOTLOADER)) +#define OSTREE_BOOTLOADER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), OSTREE_TYPE_BOOTLOADER, OstreeBootloaderInterface)) + +typedef struct _OstreeBootloader OstreeBootloader; +typedef struct _OstreeBootloaderInterface OstreeBootloaderInterface; + +struct _OstreeBootloaderInterface +{ + GTypeInterface g_iface; + + /* virtual functions */ + gboolean (* query) (OstreeBootloader *bootloader, + gboolean *out_is_active, + GCancellable *cancellable, + GError **error); + const char * (* get_name) (OstreeBootloader *self); + gboolean (* write_config) (OstreeBootloader *self, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error); + gboolean (* post_bls_sync) (OstreeBootloader *self, + GCancellable *cancellable, + GError **error); + gboolean (* is_atomic) (OstreeBootloader *self); +}; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeBootloader, g_object_unref) + +GType _ostree_bootloader_get_type (void) G_GNUC_CONST; + +gboolean _ostree_bootloader_query (OstreeBootloader *bootloader, + gboolean *out_is_active, + GCancellable *cancellable, + GError **error); + +const char *_ostree_bootloader_get_name (OstreeBootloader *self); + +gboolean _ostree_bootloader_write_config (OstreeBootloader *self, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error); + +gboolean _ostree_bootloader_post_bls_sync (OstreeBootloader *self, + GCancellable *cancellable, + GError **error); + +gboolean _ostree_bootloader_is_atomic (OstreeBootloader *self); + +G_END_DECLS diff --git a/src/libostree/ostree-chain-input-stream.c b/src/libostree/ostree-chain-input-stream.c new file mode 100644 index 0000000..dd45ca5 --- /dev/null +++ b/src/libostree/ostree-chain-input-stream.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-chain-input-stream.h" + +enum { + PROP_0, + PROP_STREAMS +}; + +G_DEFINE_TYPE (OstreeChainInputStream, ostree_chain_input_stream, G_TYPE_INPUT_STREAM) + +struct _OstreeChainInputStreamPrivate { + GPtrArray *streams; + guint index; +}; + +static void ostree_chain_input_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ostree_chain_input_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void ostree_chain_input_stream_finalize (GObject *object); +static gssize ostree_chain_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error); +static gboolean ostree_chain_input_stream_close (GInputStream *stream, + GCancellable *cancellable, + GError **error); + +static void +ostree_chain_input_stream_class_init (OstreeChainInputStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (OstreeChainInputStreamPrivate)); + + gobject_class->get_property = ostree_chain_input_stream_get_property; + gobject_class->set_property = ostree_chain_input_stream_set_property; + gobject_class->finalize = ostree_chain_input_stream_finalize; + + stream_class->read_fn = ostree_chain_input_stream_read; + stream_class->close_fn = ostree_chain_input_stream_close; + + /* + * OstreeChainInputStream:streams: (element-type GInputStream) + * + * Chain of input streams read in order. + */ + g_object_class_install_property (gobject_class, + PROP_STREAMS, + g_param_spec_pointer ("streams", + "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + +} + +static void +ostree_chain_input_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeChainInputStream *self; + + self = OSTREE_CHAIN_INPUT_STREAM (object); + + switch (prop_id) + { + case PROP_STREAMS: + self->priv->streams = g_ptr_array_ref (g_value_get_pointer (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_chain_input_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeChainInputStream *self; + + self = OSTREE_CHAIN_INPUT_STREAM (object); + + switch (prop_id) + { + case PROP_STREAMS: + g_value_set_pointer (value, self->priv->streams); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ostree_chain_input_stream_finalize (GObject *object) +{ + OstreeChainInputStream *stream; + + stream = (OstreeChainInputStream*)(object); + + g_ptr_array_unref (stream->priv->streams); + + G_OBJECT_CLASS (ostree_chain_input_stream_parent_class)->finalize (object); +} + +static void +ostree_chain_input_stream_init (OstreeChainInputStream *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + OSTREE_TYPE_CHAIN_INPUT_STREAM, + OstreeChainInputStreamPrivate); + +} + +OstreeChainInputStream * +ostree_chain_input_stream_new (GPtrArray *streams) +{ + OstreeChainInputStream *stream; + + stream = g_object_new (OSTREE_TYPE_CHAIN_INPUT_STREAM, + "streams", streams, + NULL); + + return (OstreeChainInputStream*) (stream); +} + +static gssize +ostree_chain_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + OstreeChainInputStream *self = (OstreeChainInputStream*) stream; + GInputStream *child; + gssize res = -1; + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + + if (self->priv->index >= self->priv->streams->len) + return 0; + + res = 0; + while (res == 0 && self->priv->index < self->priv->streams->len) + { + child = self->priv->streams->pdata[self->priv->index]; + res = g_input_stream_read (child, + buffer, + count, + cancellable, + error); + if (res == 0) + self->priv->index++; + } + + return res; +} + +static gboolean +ostree_chain_input_stream_close (GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + OstreeChainInputStream *self = (gpointer)stream; + guint i; + + for (i = 0; i < self->priv->streams->len; i++) + { + GInputStream *child = self->priv->streams->pdata[i]; + if (!g_input_stream_close (child, cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/libostree/ostree-chain-input-stream.h b/src/libostree/ostree-chain-input-stream.h new file mode 100644 index 0000000..a49e370 --- /dev/null +++ b/src/libostree/ostree-chain-input-stream.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#pragma once + +#ifndef __GI_SCANNER__ + +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_CHAIN_INPUT_STREAM (ostree_chain_input_stream_get_type ()) +#define OSTREE_CHAIN_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_CHAIN_INPUT_STREAM, OstreeChainInputStream)) +#define OSTREE_CHAIN_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_CHAIN_INPUT_STREAM, OstreeChainInputStreamClass)) +#define OSTREE_IS_CHAIN_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_CHAIN_INPUT_STREAM)) +#define OSTREE_IS_CHAIN_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_CHAIN_INPUT_STREAM)) +#define OSTREE_CHAIN_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_CHAIN_INPUT_STREAM, OstreeChainInputStreamClass)) + +typedef struct _OstreeChainInputStream OstreeChainInputStream; +typedef struct _OstreeChainInputStreamClass OstreeChainInputStreamClass; +typedef struct _OstreeChainInputStreamPrivate OstreeChainInputStreamPrivate; + +struct _OstreeChainInputStream +{ + GInputStream parent_instance; + + /*< private >*/ + OstreeChainInputStreamPrivate *priv; +}; + +struct _OstreeChainInputStreamClass +{ + GInputStreamClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); + void (*_g_reserved3) (void); + void (*_g_reserved4) (void); + void (*_g_reserved5) (void); +}; + +_OSTREE_PUBLIC +GType ostree_chain_input_stream_get_type (void) G_GNUC_CONST; + +_OSTREE_PUBLIC +OstreeChainInputStream * ostree_chain_input_stream_new (GPtrArray *streams); + +G_END_DECLS + +#endif diff --git a/src/libostree/ostree-checksum-input-stream.c b/src/libostree/ostree-checksum-input-stream.c new file mode 100644 index 0000000..f5f1f9e --- /dev/null +++ b/src/libostree/ostree-checksum-input-stream.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-checksum-input-stream.h" + +enum { + PROP_0, + PROP_CHECKSUM +}; + +G_DEFINE_TYPE (OstreeChecksumInputStream, ostree_checksum_input_stream, G_TYPE_FILTER_INPUT_STREAM) + +struct _OstreeChecksumInputStreamPrivate { + GChecksum *checksum; +}; + +static void ostree_checksum_input_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ostree_checksum_input_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static gssize ostree_checksum_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error); + +static void +ostree_checksum_input_stream_class_init (OstreeChecksumInputStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (OstreeChecksumInputStreamPrivate)); + + gobject_class->get_property = ostree_checksum_input_stream_get_property; + gobject_class->set_property = ostree_checksum_input_stream_set_property; + + stream_class->read_fn = ostree_checksum_input_stream_read; + + /* + * OstreeChecksumInputStream:checksum: + * + * The checksum that the stream updates. + */ + g_object_class_install_property (gobject_class, + PROP_CHECKSUM, + g_param_spec_pointer ("checksum", + "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + +} + +static void +ostree_checksum_input_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeChecksumInputStream *self; + + self = OSTREE_CHECKSUM_INPUT_STREAM (object); + + switch (prop_id) + { + case PROP_CHECKSUM: + self->priv->checksum = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_checksum_input_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeChecksumInputStream *self; + + self = OSTREE_CHECKSUM_INPUT_STREAM (object); + + switch (prop_id) + { + case PROP_CHECKSUM: + g_value_set_pointer (value, self->priv->checksum); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +ostree_checksum_input_stream_init (OstreeChecksumInputStream *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + OSTREE_TYPE_CHECKSUM_INPUT_STREAM, + OstreeChecksumInputStreamPrivate); + +} + +OstreeChecksumInputStream * +ostree_checksum_input_stream_new (GInputStream *base, + GChecksum *checksum) +{ + OstreeChecksumInputStream *stream; + + g_return_val_if_fail (G_IS_INPUT_STREAM (base), NULL); + + stream = g_object_new (OSTREE_TYPE_CHECKSUM_INPUT_STREAM, + "base-stream", base, + "checksum", checksum, + NULL); + + return (OstreeChecksumInputStream*) (stream); +} + +static gssize +ostree_checksum_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + OstreeChecksumInputStream *self = (OstreeChecksumInputStream*) stream; + GFilterInputStream *fself = (GFilterInputStream*) self; + gssize res = -1; + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + + res = g_input_stream_read (fself->base_stream, + buffer, + count, + cancellable, + error); + if (res > 0) + g_checksum_update (self->priv->checksum, buffer, res); + + return res; +} diff --git a/src/libostree/ostree-checksum-input-stream.h b/src/libostree/ostree-checksum-input-stream.h new file mode 100644 index 0000000..061b119 --- /dev/null +++ b/src/libostree/ostree-checksum-input-stream.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_CHECKSUM_INPUT_STREAM (ostree_checksum_input_stream_get_type ()) +#define OSTREE_CHECKSUM_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_CHECKSUM_INPUT_STREAM, OstreeChecksumInputStream)) +#define OSTREE_CHECKSUM_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_CHECKSUM_INPUT_STREAM, OstreeChecksumInputStreamClass)) +#define OSTREE_IS_CHECKSUM_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_CHECKSUM_INPUT_STREAM)) +#define OSTREE_IS_CHECKSUM_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_CHECKSUM_INPUT_STREAM)) +#define OSTREE_CHECKSUM_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_CHECKSUM_INPUT_STREAM, OstreeChecksumInputStreamClass)) + +typedef struct _OstreeChecksumInputStream OstreeChecksumInputStream; +typedef struct _OstreeChecksumInputStreamClass OstreeChecksumInputStreamClass; +typedef struct _OstreeChecksumInputStreamPrivate OstreeChecksumInputStreamPrivate; + +struct _OstreeChecksumInputStream +{ + GFilterInputStream parent_instance; + + /*< private >*/ + OstreeChecksumInputStreamPrivate *priv; +}; + +struct _OstreeChecksumInputStreamClass +{ + GFilterInputStreamClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); + void (*_g_reserved3) (void); + void (*_g_reserved4) (void); + void (*_g_reserved5) (void); +}; + +_OSTREE_PUBLIC +GType ostree_checksum_input_stream_get_type (void) G_GNUC_CONST; + +_OSTREE_PUBLIC +OstreeChecksumInputStream * ostree_checksum_input_stream_new (GInputStream *stream, + GChecksum *checksum); + +G_END_DECLS diff --git a/src/libostree/ostree-cmdprivate.c b/src/libostree/ostree-cmdprivate.c new file mode 100644 index 0000000..8679379 --- /dev/null +++ b/src/libostree/ostree-cmdprivate.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-cmdprivate.h" +#include "ostree-repo-private.h" +#include "ostree-core-private.h" +#include "ostree-repo-static-delta-private.h" +#include "ostree-sysroot-private.h" +#include "ostree-bootloader-grub2.h" + +#include "otutil.h" + +static gboolean +impl_ostree_generate_grub2_config (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error) +{ + return _ostree_bootloader_grub2_generate_config (sysroot, bootversion, target_fd, cancellable, error); +} + +/** + * ostree_cmdprivate: (skip) + * + * Do not call this function; it is used to share private API between + * the OSTree commandline and the library. + */ +const OstreeCmdPrivateVTable * +ostree_cmd__private__ (void) +{ + static OstreeCmdPrivateVTable table = { + _ostree_impl_system_generator, + impl_ostree_generate_grub2_config, + _ostree_repo_static_delta_dump, + _ostree_repo_static_delta_query_exists, + _ostree_repo_static_delta_delete, + _ostree_repo_verify_bindings, + _ostree_sysroot_finalize_staged, + }; + + return &table; +} diff --git a/src/libostree/ostree-cmdprivate.h b/src/libostree/ostree-cmdprivate.h new file mode 100644 index 0000000..592157b --- /dev/null +++ b/src/libostree/ostree-cmdprivate.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-types.h" + +G_BEGIN_DECLS + +gboolean _ostree_impl_system_generator (const char *ostree_cmdline, const char *normal_dir, const char *early_dir, const char *late_dir, GError **error); + +typedef struct { + gboolean (* ostree_system_generator) (const char *ostree_cmdline, const char *normal_dir, const char *early_dir, const char *late_dir, GError **error); + gboolean (* ostree_generate_grub2_config) (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error); + gboolean (* ostree_static_delta_dump) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error); + gboolean (* ostree_static_delta_query_exists) (OstreeRepo *repo, const char *delta_id, gboolean *out_exists, GCancellable *cancellable, GError **error); + gboolean (* ostree_static_delta_delete) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error); + gboolean (* ostree_repo_verify_bindings) (const char *collection_id, const char *ref_name, GVariant *commit, GError **error); + gboolean (* ostree_finalize_staged) (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error); +} OstreeCmdPrivateVTable; + +/* Note this not really "public", we just export the symbol, but not the header */ +_OSTREE_PUBLIC const OstreeCmdPrivateVTable * +ostree_cmd__private__ (void); + +G_END_DECLS diff --git a/src/libostree/ostree-core-private.h b/src/libostree/ostree-core-private.h new file mode 100644 index 0000000..5d9d948 --- /dev/null +++ b/src/libostree/ostree-core-private.h @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-core.h" +#include "otutil.h" +#include + +G_BEGIN_DECLS + +/* It's what gzip does, 9 is too slow */ +#define OSTREE_ARCHIVE_DEFAULT_COMPRESSION_LEVEL (6) + +/* Note the permissive group bits. We want to be liberal here and let individual machines + * narrow permissions as needed via umask. This is important in setups where group ownership + * can matter for repo management (like OpenShift). */ +#define DEFAULT_DIRECTORY_MODE 0775 +#define DEFAULT_REGFILE_MODE 0660 + +/* This file contains private implementation data format definitions + * read by multiple implementation .c files. + */ + +/* + * File objects are stored as a stream, with one #GVariant header, + * followed by content. + * + * The file header is of the following form: + * + * <BE guint32 containing variant length> + * u - uid + * u - gid + * u - mode + * u - rdev (must be 0) + * s - symlink target + * a(ayay) - xattrs + * + * Then the rest of the stream is data. + */ +#define _OSTREE_FILE_HEADER_GVARIANT_FORMAT G_VARIANT_TYPE ("(uuuusa(ayay))") + +/* + * A variation on %OSTREE_FILE_HEADER_GVARIANT_FORMAT, used for + * storing zlib-compressed content objects. + * + * <BE guint32 containing variant length> + * t - size + * u - uid + * u - gid + * u - mode + * u - rdev (must be 0) + * s - symlink target + * a(ayay) - xattrs + * --- + * zlib-compressed data + */ +#define _OSTREE_ZLIB_FILE_HEADER_GVARIANT_FORMAT G_VARIANT_TYPE ("(tuuuusa(ayay))") + + +GBytes *_ostree_file_header_new (GFileInfo *file_info, + GVariant *xattrs); + +GBytes *_ostree_zlib_file_header_new (GFileInfo *file_info, + GVariant *xattrs); + +gboolean +_ostree_make_temporary_symlink_at (int tmp_dirfd, + const char *target, + char **out_name, + GCancellable *cancellable, + GError **error); + +GFileInfo * _ostree_stbuf_to_gfileinfo (const struct stat *stbuf); +void _ostree_gfileinfo_to_stbuf (GFileInfo *file_info, struct stat *out_stbuf); +gboolean _ostree_gfileinfo_equal (GFileInfo *a, GFileInfo *b); +gboolean _ostree_stbuf_equal (struct stat *stbuf_a, struct stat *stbuf_b); +GFileInfo * _ostree_mode_uidgid_to_gfileinfo (mode_t mode, uid_t uid, gid_t gid); + +static inline void +_ostree_checksum_inplace_from_bytes_v (GVariant *csum_v, char *buf) +{ + const guint8*csum = ostree_checksum_bytes_peek (csum_v); + g_assert (csum); + ostree_checksum_inplace_from_bytes (csum, buf); +} + +/* XX/checksum-2.extension, but let's just use 256 for a + * bit of overkill. + */ +#define _OSTREE_LOOSE_PATH_MAX (256) + +/* GVariant format for ostree.sizes metadata entries. */ +#define _OSTREE_OBJECT_SIZES_ENTRY_SIGNATURE "ay" + +char * +_ostree_get_relative_object_path (const char *checksum, + OstreeObjectType type, + gboolean compressed); + + +char * +_ostree_get_relative_static_delta_path (const char *from, + const char *to, + const char *target); + +char * +_ostree_get_relative_static_delta_superblock_path (const char *from, + const char *to); + +char * +_ostree_get_relative_static_delta_detachedmeta_path (const char *from, + const char *to); + +char * +_ostree_get_relative_static_delta_part_path (const char *from, + const char *to, + guint i); + +static inline char * _ostree_get_commitpartial_path (const char *checksum) +{ + return g_strconcat ("state/", checksum, ".commitpartial", NULL); +} + +gboolean +_ostree_validate_ref_fragment (const char *fragment, + GError **error); + + +gboolean +_ostree_validate_bareuseronly_mode (guint32 mode, + const char *checksum, + GError **error); +static inline gboolean +_ostree_validate_bareuseronly_mode_finfo (GFileInfo *finfo, + const char *checksum, + GError **error) +{ + const guint32 content_mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode"); + return _ostree_validate_bareuseronly_mode (content_mode, checksum, error); +} + +gboolean +_ostree_compare_object_checksum (OstreeObjectType objtype, + const char *expected, + const char *actual, + GError **error); + +gboolean +_ostree_parse_delta_name (const char *delta_name, + char **out_from, + char **out_to, + GError **error); + +void +_ostree_loose_path (char *buf, + const char *checksum, + OstreeObjectType objtype, + OstreeRepoMode repo_mode); + +gboolean _ostree_validate_structureof_metadata (OstreeObjectType objtype, + GVariant *commit, + GError **error); + +gboolean +_ostree_verify_metadata_object (OstreeObjectType objtype, + const char *expected_checksum, + GVariant *metadata, + GError **error); + + +#define _OSTREE_METADATA_GPGSIGS_NAME "ostree.gpgsigs" +#define _OSTREE_METADATA_GPGSIGS_TYPE G_VARIANT_TYPE ("aay") + +static inline gboolean +_ostree_repo_mode_is_bare (OstreeRepoMode mode) +{ + return + mode == OSTREE_REPO_MODE_BARE || + mode == OSTREE_REPO_MODE_BARE_USER || + mode == OSTREE_REPO_MODE_BARE_USER_ONLY; +} + +#ifndef OSTREE_DISABLE_GPGME +GVariant * +_ostree_detached_metadata_append_gpg_sig (GVariant *existing_metadata, + GBytes *signature_bytes); +#endif + +GFile * +_ostree_get_default_sysroot_path (void); + +_OSTREE_PUBLIC +gboolean +_ostree_raw_file_to_archive_stream (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + guint compression_level, + GInputStream **out_input, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_compare_timestamps (const char *current_rev, + guint64 current_ts, + const char *new_rev, + guint64 new_ts, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c new file mode 100644 index 0000000..523f57c --- /dev/null +++ b/src/libostree/ostree-core.c @@ -0,0 +1,2722 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include "libglnx.h" +#include "ostree.h" +#include "ostree-core-private.h" +#include "ostree-chain-input-stream.h" +#include "ostree-varint.h" +#include "otutil.h" + +/* Generic ABI checks */ +G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE == 0); +G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE_Z2 == 1); +G_STATIC_ASSERT(OSTREE_REPO_MODE_ARCHIVE == OSTREE_REPO_MODE_ARCHIVE_Z2); +G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER == 2); +G_STATIC_ASSERT(OSTREE_REPO_MODE_BARE_USER_ONLY == 3); + +static GBytes *variant_to_lenprefixed_buffer (GVariant *variant); + +#define ALIGN_VALUE(this, boundary) \ + (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) + +/* Return a copy of @input suitable for addition to + * a GError message; newlines are quashed, the value + * is forced to be UTF-8, is truncated to @maxlen (if maxlen != -1). + */ +static char * +quash_string_for_error_message (const char *input, + ssize_t len, + ssize_t maxlen) +{ + if (len == -1) + len = strlen (input); + if (maxlen != -1 && maxlen < len) + len = maxlen; +#if GLIB_CHECK_VERSION(2, 52, 0) + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + char *buf = g_utf8_make_valid (input, len); + G_GNUC_END_IGNORE_DEPRECATIONS +#else + char *buf = g_strndup (input, len); +#endif + for (char *iter = buf; iter && *iter; iter++) + { + char c = *iter; + if (c == '\n') + *iter = ' '; +#if !GLIB_CHECK_VERSION(2, 52, 0) + /* No g_utf8_make_valid()? OK, let's just brute force this. */ + if (!g_ascii_isprint (c)) + *iter = ' '; +#endif + } + return buf; +} + +static gboolean +file_header_parse (GVariant *metadata, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GError **error); +static gboolean +zlib_file_header_parse (GVariant *metadata, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GError **error); + +/** + * SECTION:ostree-core + * @title: Core repository-independent functions + * @short_description: Create, validate, and convert core data types + * + * These functions implement repository-independent algorithms for + * operating on the core OSTree data formats, such as converting + * #GFileInfo into a #GVariant. + * + * There are 4 types of objects; file, dirmeta, tree, and commit. The + * last 3 are metadata, and the file object is the only content object + * type. + * + * All metadata objects are stored as #GVariant (big endian). The + * rationale for this is the same as that of the ext{2,3,4} family of + * filesystems; most developers will be using LE, and so it's better + * to continually test the BE->LE swap. + * + * The file object is a custom format in order to support streaming. + */ + +const GVariantType * +ostree_metadata_variant_type (OstreeObjectType objtype) +{ + switch (objtype) + { + case OSTREE_OBJECT_TYPE_DIR_TREE: + return OSTREE_TREE_GVARIANT_FORMAT; + case OSTREE_OBJECT_TYPE_DIR_META: + return OSTREE_DIRMETA_GVARIANT_FORMAT; + case OSTREE_OBJECT_TYPE_COMMIT: + return OSTREE_COMMIT_GVARIANT_FORMAT; + default: + g_assert_not_reached (); + } +} + +/** + * ostree_validate_checksum_string: + * @sha256: SHA256 hex string + * @error: Error + * + * Use this function to see if input strings are checksums. + * + * Returns: %TRUE if @sha256 is a valid checksum string, %FALSE otherwise + */ +gboolean +ostree_validate_checksum_string (const char *sha256, + GError **error) +{ + return ostree_validate_structureof_checksum_string (sha256, error); +} + +/* This used to allow leading - and ., but was changed in + * https://github.com/ostreedev/ostree/pull/1286 + */ +#define OSTREE_REF_FRAGMENT_REGEXP "[\\w\\d][-._\\w\\d]*" +#define OSTREE_REF_REGEXP "(?:" OSTREE_REF_FRAGMENT_REGEXP "/)*" OSTREE_REF_FRAGMENT_REGEXP +#define OSTREE_REMOTE_NAME_REGEXP OSTREE_REF_FRAGMENT_REGEXP + +/** + * ostree_parse_refspec: + * @refspec: A "refspec" string + * @out_remote: (out) (nullable) (optional): Return location for the remote name, + * or %NULL if the refspec refs to a local ref + * @out_ref: (out) (not nullable) (optional): Return location for the ref name + * @error: Error + * + * Split a refspec like `gnome-ostree:gnome-ostree/buildmaster` or just + * `gnome-ostree/buildmaster` into two parts. In the first case, @out_remote + * will be set to `gnome-ostree`, and @out_ref to `gnome-ostree/buildmaster`. + * In the second case (a local ref), @out_remote will be %NULL, and @out_ref + * will be `gnome-ostree/buildmaster`. In both cases, %TRUE will be returned. + * + * Returns: %TRUE on successful parsing, %FALSE otherwise + */ +gboolean +ostree_parse_refspec (const char *refspec, + char **out_remote, + char **out_ref, + GError **error) +{ + static GRegex *regex; + static gsize regex_initialized; + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^(" OSTREE_REMOTE_NAME_REGEXP ":)?(" OSTREE_REF_REGEXP ")$", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + g_autoptr(GMatchInfo) match = NULL; + if (!g_regex_match (regex, refspec, 0, &match)) + return glnx_throw (error, "Invalid refspec %s", refspec); + + g_autofree char *remote = g_match_info_fetch (match, 1); + if (*remote == '\0') + { + g_clear_pointer (&remote, g_free); + } + else + { + /* Trim the : */ + remote[strlen(remote)-1] = '\0'; + } + + if (out_remote) + *out_remote = g_steal_pointer (&remote); + if (out_ref != NULL) + *out_ref = g_match_info_fetch (match, 2); + return TRUE; +} + +gboolean +_ostree_validate_ref_fragment (const char *fragment, + GError **error) +{ + static GRegex *regex; + static gsize regex_initialized; + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^" OSTREE_REF_FRAGMENT_REGEXP "$", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + g_autoptr(GMatchInfo) match = NULL; + if (!g_regex_match (regex, fragment, 0, &match)) + return glnx_throw (error, "Invalid ref fragment '%s'", fragment); + + return TRUE; +} + +/** + * ostree_validate_rev: + * @rev: A revision string + * @error: Error + * + * Returns: %TRUE if @rev is a valid ref string + */ +gboolean +ostree_validate_rev (const char *rev, + GError **error) +{ + g_autoptr(GMatchInfo) match = NULL; + + static gsize regex_initialized; + static GRegex *regex; + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^" OSTREE_REF_REGEXP "$", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + if (!g_regex_match (regex, rev, 0, &match)) + return glnx_throw (error, "Invalid ref name %s", rev); + + return TRUE; +} + +/** + * ostree_validate_remote_name: + * @remote_name: A remote name + * @error: Error + * + * Returns: %TRUE if @remote_name is a valid remote name + * Since: 2017.8 + */ +gboolean +ostree_validate_remote_name (const char *remote_name, + GError **error) +{ + g_autoptr(GMatchInfo) match = NULL; + + static gsize regex_initialized; + static GRegex *regex; + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^" OSTREE_REMOTE_NAME_REGEXP "$", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + if (!g_regex_match (regex, remote_name, 0, &match)) + return glnx_throw (error, "Invalid remote name %s", remote_name); + + return TRUE; +} + +/** + * ostree_validate_collection_id: + * @collection_id: (nullable): A collection ID + * @error: Error + * + * Check whether the given @collection_id is valid. Return an error if it is + * invalid or %NULL. + * + * Valid collection IDs are reverse DNS names: + * * They are composed of 1 or more elements separated by a period (`.`) character. + * All elements must contain at least one character. + * * Each element must only contain the ASCII characters `[A-Z][a-z][0-9]_` and must not + * begin with a digit. + * * They must contain at least one `.` (period) character (and thus at least two elements). + * * They must not begin with a `.` (period) character. + * * They must not exceed 255 characters in length. + * + * (This makes their format identical to D-Bus interface names, for consistency.) + * + * Returns: %TRUE if @collection_id is a valid collection ID, %FALSE if it is invalid + * or %NULL + * Since: 2018.6 + */ +gboolean +ostree_validate_collection_id (const char *collection_id, GError **error) +{ + /* Abuse g_dbus_is_interface_name(), since collection IDs have the same format. */ + if (collection_id == NULL || !g_dbus_is_interface_name (collection_id)) + return glnx_throw (error, "Invalid collection ID %s", collection_id); + + return TRUE; +} + +/* The file header is part of the "object stream" format + * that's not compressed. It's comprised of uid,gid,mode, + * and possibly symlink targets from @file_info, as well + * as @xattrs (which if NULL, is taken to be the empty set). + */ +GBytes * +_ostree_file_header_new (GFileInfo *file_info, + GVariant *xattrs) +{ + + guint32 uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid"); + guint32 gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid"); + guint32 mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + + const char *symlink_target; + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) + symlink_target = g_file_info_get_symlink_target (file_info); + else + symlink_target = ""; + + g_autoptr(GVariant) tmp_xattrs = NULL; + if (xattrs == NULL) + tmp_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); + + g_autoptr(GVariant) ret = g_variant_new ("(uuuus@a(ayay))", GUINT32_TO_BE (uid), + GUINT32_TO_BE (gid), GUINT32_TO_BE (mode), 0, + symlink_target, xattrs ?: tmp_xattrs); + return variant_to_lenprefixed_buffer (g_variant_ref_sink (ret)); +} + +/* Like _ostree_file_header_new(), but used for the compressed format in archive + * repositories. This format hence lives on disk; normally the uncompressed + * stream format doesn't. Instead for "bare" repositories, the file data is + * stored directly, or for the special case of bare-user repositories, as a + * user.ostreemeta xattr. + */ +GBytes * +_ostree_zlib_file_header_new (GFileInfo *file_info, + GVariant *xattrs) +{ + guint64 size = g_file_info_get_size (file_info); + guint32 uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid"); + guint32 gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid"); + guint32 mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + + const char *symlink_target; + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) + symlink_target = g_file_info_get_symlink_target (file_info); + else + symlink_target = ""; + + g_autoptr(GVariant) tmp_xattrs = NULL; + if (xattrs == NULL) + tmp_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); + + g_autoptr(GVariant) ret = g_variant_new ("(tuuuus@a(ayay))", + GUINT64_TO_BE (size), GUINT32_TO_BE (uid), + GUINT32_TO_BE (gid), GUINT32_TO_BE (mode), 0, + symlink_target, xattrs ?: tmp_xattrs); + return variant_to_lenprefixed_buffer (g_variant_ref_sink (ret)); +} + +/* Serialize a variant to a buffer prefixed with its length. The variant will + * have an 8-byte alignment so it can be safely used with `mmap()`. + */ +static GBytes * +variant_to_lenprefixed_buffer (GVariant *variant) +{ + /* This string is really a binary memory buffer */ + g_autoptr(GString) buf = g_string_new (NULL); + /* Write variant size */ + const guint64 variant_size = g_variant_get_size (variant); + g_assert (variant_size < G_MAXUINT32); + const guint32 variant_size_u32_be = GUINT32_TO_BE((guint32) variant_size); + + g_string_append_len (buf, (char*)&variant_size_u32_be, sizeof (variant_size_u32_be)); + const gsize alignment_offset = sizeof (variant_size_u32_be); + + /* Write NULs for alignment. At the moment this is a constant 4 bytes (i.e. + * align to 8, since the length is 4 bytes). For now, I decided to keep some + * of the (now legacy) more generic logic here in case we want to revive it + * later. + */ + const guint alignment = 8; + const guchar padding_nuls[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + guint bits; + if (alignment == 8) + bits = alignment_offset & 7; /* mod 8 */ + else + bits = alignment_offset & 3; /* mod 4 */ + const guint padding_len = alignment - bits; + + if (bits > 0) + g_string_append_len (buf, (char*)padding_nuls, padding_len); + + g_string_append_len (buf, (char*)g_variant_get_data (variant), g_variant_get_size (variant)); + return g_string_free_to_bytes (g_steal_pointer (&buf)); +} + +/* + * header_and_input_to_stream: + * @file_header: A file header + * @input: File raw content stream + * @out_input: (out): Serialized object stream + * @cancellable: Cancellable + * @error: Error + * + * Combines @file_header and @input into a single stream. + */ +static gboolean +header_and_input_to_stream (GBytes *file_header, + GInputStream *input, + GInputStream **out_input, + GCancellable *cancellable, + GError **error) +{ + /* Our result stream chain */ + g_autoptr(GPtrArray) streams = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + + /* Append the header to the chain */ + g_autoptr(GInputStream) header_in_stream = g_memory_input_stream_new_from_bytes (file_header); + + g_ptr_array_add (streams, g_object_ref (header_in_stream)); + + /* And if we have an input stream, append that */ + if (input) + g_ptr_array_add (streams, g_object_ref (input)); + + /* Return the result stream */ + g_autoptr(GInputStream) ret_input = (GInputStream*)ostree_chain_input_stream_new (streams); + ot_transfer_out_value (out_input, &ret_input); + + return TRUE; +} + +/* Convert file metadata + file content into an archive-format stream. */ +gboolean +_ostree_raw_file_to_archive_stream (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + guint compression_level, + GInputStream **out_input, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GInputStream) zlib_input = NULL; + if (input != NULL) + { + g_autoptr(GConverter) zlib_compressor = + G_CONVERTER (g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW, compression_level)); + zlib_input = g_converter_input_stream_new (input, zlib_compressor); + } + g_autoptr(GBytes) file_header = _ostree_zlib_file_header_new (file_info, xattrs); + return header_and_input_to_stream (file_header, + zlib_input, + out_input, + cancellable, + error); +} + +/** + * ostree_raw_file_to_archive_z2_stream: + * @input: File raw content stream + * @file_info: A file info + * @xattrs: (allow-none): Optional extended attributes + * @out_input: (out): Serialized object stream + * @cancellable: Cancellable + * @error: Error + * + * Convert from a "bare" file representation into an + * OSTREE_OBJECT_TYPE_FILE stream suitable for ostree pull. + * + * Since: 2016.6 + */ +gboolean +ostree_raw_file_to_archive_z2_stream (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream **out_input, + GCancellable *cancellable, + GError **error) +{ + return _ostree_raw_file_to_archive_stream (input, file_info, xattrs, + OSTREE_ARCHIVE_DEFAULT_COMPRESSION_LEVEL, + out_input, cancellable, error); +} + +/** + * ostree_raw_file_to_archive_z2_stream_with_options: + * @input: File raw content stream + * @file_info: A file info + * @xattrs: (allow-none): Optional extended attributes + * @options: (nullable): A GVariant `a{sv}` with an extensible set of flags + * @out_input: (out): Serialized object stream + * @cancellable: Cancellable + * @error: Error + * + * Like ostree_raw_file_to_archive_z2_stream(), but supports an extensible set + * of flags. The following flags are currently defined: + * + * - `compression-level` (`i`): Level of compression to use, 0–9, with 0 being + * the least compression, and <0 giving the default level (currently 6). + * + * Since: 2017.3 + */ +gboolean +ostree_raw_file_to_archive_z2_stream_with_options (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + GVariant *options, + GInputStream **out_input, + GCancellable *cancellable, + GError **error) +{ + gint compression_level = -1; + + if (options) + (void) g_variant_lookup (options, "compression-level", "i", &compression_level); + + if (compression_level < 0) + compression_level = OSTREE_ARCHIVE_DEFAULT_COMPRESSION_LEVEL; + + return _ostree_raw_file_to_archive_stream (input, file_info, xattrs, + compression_level, + out_input, cancellable, error); +} + +/** + * ostree_raw_file_to_content_stream: + * @input: File raw content stream + * @file_info: A file info + * @xattrs: (allow-none): Optional extended attributes + * @out_input: (out): Serialized object stream + * @out_length: (out): Length of stream + * @cancellable: Cancellable + * @error: Error + * + * Convert from a "bare" file representation into an + * OSTREE_OBJECT_TYPE_FILE stream. This is a fundamental operation + * for writing data to an #OstreeRepo. + */ +gboolean +ostree_raw_file_to_content_stream (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream **out_input, + guint64 *out_length, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GBytes) file_header = _ostree_file_header_new (file_info, xattrs); + if (!header_and_input_to_stream (file_header, + input, + out_input, + cancellable, + error)) + return FALSE; + if (out_length) + *out_length = g_bytes_get_size (file_header) + g_file_info_get_size (file_info); + return TRUE; +} + +/** + * ostree_content_stream_parse: + * @compressed: Whether or not the stream is zlib-compressed + * @input: Object content stream + * @input_length: Length of stream + * @trusted: If %TRUE, assume the content has been validated + * @out_input: (out): The raw file content stream + * @out_file_info: (out): Normal metadata + * @out_xattrs: (out): Extended attributes + * @cancellable: Cancellable + * @error: Error + * + * The reverse of ostree_raw_file_to_content_stream(); this function + * converts an object content stream back into components. + */ +gboolean +ostree_content_stream_parse (gboolean compressed, + GInputStream *input, + guint64 input_length, + gboolean trusted, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + guint32 archive_header_size; + guchar dummy[4]; + gsize bytes_read; + + if (!g_input_stream_read_all (input, + &archive_header_size, 4, &bytes_read, + cancellable, error)) + return FALSE; + archive_header_size = GUINT32_FROM_BE (archive_header_size); + if (archive_header_size > input_length) + return glnx_throw (error, "File header size %u exceeds size %" G_GUINT64_FORMAT, + (guint)archive_header_size, input_length); + else if (archive_header_size == 0) + return glnx_throw (error, "File header size is zero"); + + /* Skip over padding */ + if (!g_input_stream_read_all (input, + dummy, 4, &bytes_read, + cancellable, error)) + return FALSE; + + g_autofree guchar *buf = g_malloc (archive_header_size); + if (!g_input_stream_read_all (input, buf, archive_header_size, &bytes_read, + cancellable, error)) + return FALSE; + g_autoptr(GVariant) file_header = + g_variant_ref_sink(g_variant_new_from_data (compressed ? _OSTREE_ZLIB_FILE_HEADER_GVARIANT_FORMAT : _OSTREE_FILE_HEADER_GVARIANT_FORMAT, + buf, archive_header_size, trusted, + g_free, buf)); + buf = NULL; + g_autoptr(GFileInfo) ret_file_info = NULL; + g_autoptr(GVariant) ret_xattrs = NULL; + if (compressed) + { + if (!zlib_file_header_parse (file_header, + &ret_file_info, + out_xattrs ? &ret_xattrs : NULL, + error)) + return FALSE; + } + else + { + if (!file_header_parse (file_header, + &ret_file_info, + out_xattrs ? &ret_xattrs : NULL, + error)) + return FALSE; + g_file_info_set_size (ret_file_info, input_length - archive_header_size - 8); + } + + g_autoptr(GInputStream) ret_input = NULL; + if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR + && out_input) + { + /* Give the input stream at its current position as return value; + * assuming the caller doesn't seek, this should be fine. We might + * want to wrap it though in a non-seekable stream. + **/ + if (compressed) + { + g_autoptr(GConverter) zlib_decomp = (GConverter*)g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW); + ret_input = g_converter_input_stream_new (input, zlib_decomp); + } + else + ret_input = g_object_ref (input); + } + + ot_transfer_out_value (out_input, &ret_input); + ot_transfer_out_value (out_file_info, &ret_file_info); + ot_transfer_out_value (out_xattrs, &ret_xattrs); + return TRUE; +} + +/** + * ostree_content_file_parse_at: + * @compressed: Whether or not the stream is zlib-compressed + * @parent_dfd: Directory file descriptor + * @path: Subpath + * @trusted: If %TRUE, assume the content has been validated + * @out_input: (out): The raw file content stream + * @out_file_info: (out): Normal metadata + * @out_xattrs: (out): Extended attributes + * @cancellable: Cancellable + * @error: Error + * + * A thin wrapper for ostree_content_stream_parse(); this function + * converts an object content stream back into components. + */ +gboolean +ostree_content_file_parse_at (gboolean compressed, + int parent_dfd, + const char *path, + gboolean trusted, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (parent_dfd, path, TRUE, &fd, error)) + return FALSE; + + struct stat stbuf; + if (!glnx_fstat (fd, &stbuf, error)) + return FALSE; + + g_autoptr(GInputStream) file_input = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE); + + g_autoptr(GFileInfo) ret_file_info = NULL; + g_autoptr(GVariant) ret_xattrs = NULL; + g_autoptr(GInputStream) ret_input = NULL; + if (!ostree_content_stream_parse (compressed, file_input, stbuf.st_size, trusted, + out_input ? &ret_input : NULL, + &ret_file_info, &ret_xattrs, + cancellable, error)) + return FALSE; + + ot_transfer_out_value (out_input, &ret_input); + ot_transfer_out_value (out_file_info, &ret_file_info); + ot_transfer_out_value (out_xattrs, &ret_xattrs); + return TRUE; +} + +/** + * ostree_content_file_parse: + * @compressed: Whether or not the stream is zlib-compressed + * @content_path: Path to file containing content + * @trusted: If %TRUE, assume the content has been validated + * @out_input: (out): The raw file content stream + * @out_file_info: (out): Normal metadata + * @out_xattrs: (out): Extended attributes + * @cancellable: Cancellable + * @error: Error + * + * A thin wrapper for ostree_content_stream_parse(); this function + * converts an object content stream back into components. + */ +gboolean +ostree_content_file_parse (gboolean compressed, + GFile *content_path, + gboolean trusted, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + return ostree_content_file_parse_at (compressed, AT_FDCWD, + gs_file_get_path_cached (content_path), + trusted, + out_input, out_file_info, out_xattrs, + cancellable, error); +} + +static gboolean +break_symhardlink (int dfd, + const char *path, + struct stat *stbuf, + GLnxFileCopyFlags copyflags, + GCancellable *cancellable, + GError **error) +{ + guint count; + gboolean copy_success = FALSE; + char *path_tmp = glnx_strjoina (path, ".XXXXXX"); + + for (count = 0; count < 100; count++) + { + g_autoptr(GError) tmp_error = NULL; + + glnx_gen_temp_name (path_tmp); + + if (!glnx_file_copy_at (dfd, path, stbuf, dfd, path_tmp, copyflags, + cancellable, &tmp_error)) + { + if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + continue; + g_propagate_error (error, g_steal_pointer (&tmp_error)); + return FALSE; + } + + copy_success = TRUE; + break; + } + + if (!copy_success) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "Exceeded limit of %u file creation attempts", count); + return FALSE; + } + + if (!glnx_renameat (dfd, path_tmp, dfd, path, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_break_hardlink: + * @dfd: Directory fd + * @path: Path relative to @dfd + * @skip_xattrs: Do not copy extended attributes + * @error: error + * + * In many cases using libostree, a program may need to "break" + * hardlinks by performing a copy. For example, in order to + * logically append to a file. + * + * This function performs full copying, including e.g. extended + * attributes and permissions of both regular files and symbolic links. + * + * If the file is not hardlinked, this function does nothing and + * returns successfully. + * + * This function does not perform synchronization via `fsync()` or + * `fdatasync()`; the idea is this will commonly be done as part + * of an `ostree_repo_commit_transaction()`, which itself takes + * care of synchronization. + * + * Since: 2017.15 + */ +gboolean ostree_break_hardlink (int dfd, + const char *path, + gboolean skip_xattrs, + GCancellable *cancellable, + GError **error) +{ + struct stat stbuf; + + if (!glnx_fstatat (dfd, path, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + if (stbuf.st_nlink <= 1) + return TRUE; /* Note early return */ + + const GLnxFileCopyFlags copyflags = skip_xattrs ? GLNX_FILE_COPY_NOXATTRS : 0; + + if (S_ISREG (stbuf.st_mode)) + /* Note it's now completely safe to copy a file to itself, + * as glnx_file_copy_at() is documented to do an O_TMPFILE + rename() + * with GLNX_FILE_COPY_OVERWRITE. + */ + return glnx_file_copy_at (dfd, path, &stbuf, dfd, path, + copyflags | GLNX_FILE_COPY_OVERWRITE, + cancellable, error); + else if (S_ISLNK (stbuf.st_mode)) + return break_symhardlink (dfd, path, &stbuf, copyflags, + cancellable, error); + else + return glnx_throw (error, "Unsupported type for entry '%s'", path); + + return TRUE; +} + +/** + * ostree_checksum_file_from_input: + * @file_info: File information + * @xattrs: (allow-none): Optional extended attributes + * @in: (allow-none): File content, should be %NULL for symbolic links + * @objtype: Object type + * @out_csum: (out) (array fixed-size=32): Return location for binary checksum + * @cancellable: Cancellable + * @error: Error + * + * Compute the OSTree checksum for a given input. + */ +gboolean +ostree_checksum_file_from_input (GFileInfo *file_info, + GVariant *xattrs, + GInputStream *in, + OstreeObjectType objtype, + guchar **out_csum, + GCancellable *cancellable, + GError **error) +{ + + g_auto(OtChecksum) checksum = { 0, }; + ot_checksum_init (&checksum); + + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + { + if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error)) + return FALSE; + } + else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) + { + g_autoptr(GVariant) dirmeta = ostree_create_directory_metadata (file_info, xattrs); + ot_checksum_update (&checksum, g_variant_get_data (dirmeta), + g_variant_get_size (dirmeta)); + } + else + { + g_autoptr(GBytes) file_header = _ostree_file_header_new (file_info, xattrs); + + ot_checksum_update_bytes (&checksum, file_header); + + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) + { + if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error)) + return FALSE; + } + } + + *out_csum = g_malloc (OSTREE_SHA256_DIGEST_LEN); + ot_checksum_get_digest (&checksum, *out_csum, OSTREE_SHA256_DIGEST_LEN); + return TRUE; +} + +/** + * ostree_checksum_file: + * @f: File path + * @objtype: Object type + * @out_csum: (out) (array fixed-size=32): Return location for binary checksum + * @cancellable: Cancellable + * @error: Error + * + * Compute the OSTree checksum for a given file. + */ +gboolean +ostree_checksum_file (GFile *f, + OstreeObjectType objtype, + guchar **out_csum, + GCancellable *cancellable, + GError **error) +{ + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + g_autoptr(GFileInfo) file_info = + g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!file_info) + return FALSE; + + g_autoptr(GInputStream) in = NULL; + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) + { + in = (GInputStream*)g_file_read (f, cancellable, error); + if (!in) + return FALSE; + } + + g_autoptr(GVariant) xattrs = NULL; + if (objtype == OSTREE_OBJECT_TYPE_FILE) + { + if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f), + &xattrs, cancellable, error)) + return FALSE; + } + + g_autofree guchar *ret_csum = NULL; + if (!ostree_checksum_file_from_input (file_info, xattrs, in, objtype, + &ret_csum, cancellable, error)) + return FALSE; + + ot_transfer_out_value(out_csum, &ret_csum); + return TRUE; +} + +/** + * ostree_checksum_file_at: + * @dfd: Directory file descriptor + * @path: Subpath + * @stbuf (allow-none): Optional stat buffer + * @objtype: Object type + * @flags: Flags + * @out_checksum (out) (transfer full): Return location for hex checksum + * @cancellable: Cancellable + * @error: Error + * + * Compute the OSTree checksum for a given file. This is an fd-relative version + * of ostree_checksum_file() which also takes flags and fills in a caller + * allocated buffer. + * + * Since: 2017.13 + */ +gboolean +ostree_checksum_file_at (int dfd, + const char *path, + struct stat *stbuf, + OstreeObjectType objtype, + OstreeChecksumFlags flags, + char **out_checksum, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (out_checksum != NULL, FALSE); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + struct stat local_stbuf; + if (stbuf == NULL) + { + stbuf = &local_stbuf; + if (!glnx_fstatat (dfd, path, stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + } + + g_autoptr(GFileInfo) file_info = _ostree_stbuf_to_gfileinfo (stbuf); + + g_autoptr(GInputStream) in = NULL; + if (S_ISREG (stbuf->st_mode)) + { + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd, path, FALSE, &fd, error)) + return FALSE; + in = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE); + } + else if (S_ISLNK (stbuf->st_mode)) + { + if (!ot_readlinkat_gfile_info (dfd, path, file_info, cancellable, error)) + return FALSE; + } + + const gboolean ignore_xattrs = + ((flags & OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS) > 0); + + g_autoptr(GVariant) xattrs = NULL; + if (!ignore_xattrs && objtype == OSTREE_OBJECT_TYPE_FILE) + { + if (!glnx_dfd_name_get_all_xattrs (dfd, path, &xattrs, cancellable, error)) + return FALSE; + } + + g_autofree guchar *csum_bytes = NULL; + if (!ostree_checksum_file_from_input (file_info, xattrs, in, objtype, + &csum_bytes, cancellable, error)) + return FALSE; + + *out_checksum = ostree_checksum_from_bytes (csum_bytes); + return TRUE; +} + +typedef struct { + GFile *f; + OstreeObjectType objtype; + guchar *csum; +} ChecksumFileAsyncData; + +static void +checksum_file_async_thread (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + GError *error = NULL; + ChecksumFileAsyncData *data; + guchar *csum = NULL; + + data = g_simple_async_result_get_op_res_gpointer (res); + if (!ostree_checksum_file (data->f, data->objtype, &csum, cancellable, &error)) + g_simple_async_result_take_error (res, error); + else + data->csum = csum; +} + +static void +checksum_file_async_data_free (gpointer datap) +{ + ChecksumFileAsyncData *data = datap; + + g_object_unref (data->f); + g_free (data->csum); + g_free (data); +} + +/** + * ostree_checksum_file_async: + * @f: File path + * @objtype: Object type + * @io_priority: Priority for operation, see %G_IO_PRIORITY_DEFAULT + * @cancellable: Cancellable + * @callback: Invoked when operation is complete + * @user_data: Data for @callback + * + * Asynchronously compute the OSTree checksum for a given file; + * complete with ostree_checksum_file_async_finish(). + */ +void +ostree_checksum_file_async (GFile *f, + OstreeObjectType objtype, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + ChecksumFileAsyncData *data; + + data = g_new0 (ChecksumFileAsyncData, 1); + data->f = g_object_ref (f); + data->objtype = objtype; + + res = g_simple_async_result_new (G_OBJECT (f), callback, user_data, ostree_checksum_file_async); + g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)checksum_file_async_data_free); + + g_simple_async_result_run_in_thread (res, checksum_file_async_thread, io_priority, cancellable); + g_object_unref (res); +} + +/** + * ostree_checksum_file_async_finish: + * @f: File path + * @result: Async result + * @out_csum: (out) (array fixed-size=32): Return location for binary checksum + * @error: Error + * + * Finish computing the OSTree checksum for a given file; see + * ostree_checksum_file_async(). + */ +gboolean +ostree_checksum_file_async_finish (GFile *f, + GAsyncResult *result, + guchar **out_csum, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + ChecksumFileAsyncData *data; + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == ostree_checksum_file_async); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + data = g_simple_async_result_get_op_res_gpointer (simple); + /* Transfer ownership */ + *out_csum = data->csum; + data->csum = NULL; + return TRUE; +} + +/* Common helper to compare checksums for an object, so we have a consistent + * error message. + */ +gboolean +_ostree_compare_object_checksum (OstreeObjectType objtype, + const char *expected, + const char *actual, + GError **error) +{ + if (!g_str_equal (expected, actual)) + return glnx_throw (error, "Corrupted %s object; checksum expected='%s' actual='%s'", + ostree_object_type_to_string (objtype), + expected, actual); + return TRUE; +} + +/** + * ostree_create_directory_metadata: + * @dir_info: a #GFileInfo containing directory information + * @xattrs: (allow-none): Optional extended attributes + * + * Returns: (transfer full): A new #GVariant containing %OSTREE_OBJECT_TYPE_DIR_META + */ +GVariant * +ostree_create_directory_metadata (GFileInfo *dir_info, + GVariant *xattrs) +{ + GVariant *ret_metadata = NULL; + + ret_metadata = g_variant_new ("(uuu@a(ayay))", + GUINT32_TO_BE (g_file_info_get_attribute_uint32 (dir_info, "unix::uid")), + GUINT32_TO_BE (g_file_info_get_attribute_uint32 (dir_info, "unix::gid")), + GUINT32_TO_BE (g_file_info_get_attribute_uint32 (dir_info, "unix::mode")), + xattrs ? xattrs : g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); + g_variant_ref_sink (ret_metadata); + + return ret_metadata; +} + +/* Create a randomly-named symbolic link in @tempdir which points to + * @target. The filename will be returned in @out_file. + * + * The reason this odd function exists is that the repo should only + * contain objects in their final state. For bare repositories, we + * need to first create the symlink, then chown it, and apply all + * extended attributes, before finally rename()ing it into place. + * + * Furthermore for checkouts, we use this to implement union mode + * where we override existing files via tempfile+rename(). + */ +gboolean +_ostree_make_temporary_symlink_at (int tmp_dirfd, + const char *target, + char **out_name, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *tmpname = g_strdup ("tmplink.XXXXXX"); + const int max_attempts = 128; + guint i; + + for (i = 0; i < max_attempts; i++) + { + glnx_gen_temp_name (tmpname); + if (symlinkat (target, tmp_dirfd, tmpname) < 0) + { + if (errno == EEXIST) + continue; + else + return glnx_throw_errno (error); + } + else + break; + } + if (i == max_attempts) + return glnx_throw (error, "Exhausted attempts to open temporary file"); + + if (out_name) + *out_name = g_steal_pointer (&tmpname); + return TRUE; +} + + +/** + * ostree_object_type_to_string: + * @objtype: an #OstreeObjectType + * + * Serialize @objtype to a string; this is used for file extensions. + */ +const char * +ostree_object_type_to_string (OstreeObjectType objtype) +{ + switch (objtype) + { + case OSTREE_OBJECT_TYPE_FILE: + return "file"; + case OSTREE_OBJECT_TYPE_DIR_TREE: + return "dirtree"; + case OSTREE_OBJECT_TYPE_DIR_META: + return "dirmeta"; + case OSTREE_OBJECT_TYPE_COMMIT: + return "commit"; + case OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT: + return "tombstone-commit"; + case OSTREE_OBJECT_TYPE_COMMIT_META: + return "commitmeta"; + case OSTREE_OBJECT_TYPE_PAYLOAD_LINK: + return "payload-link"; + default: + g_assert_not_reached (); + return NULL; + } +} + +/** + * ostree_object_type_from_string: + * @str: A stringified version of #OstreeObjectType + * + * The reverse of ostree_object_type_to_string(). + */ +OstreeObjectType +ostree_object_type_from_string (const char *str) +{ + if (!strcmp (str, "file")) + return OSTREE_OBJECT_TYPE_FILE; + else if (!strcmp (str, "dirtree")) + return OSTREE_OBJECT_TYPE_DIR_TREE; + else if (!strcmp (str, "dirmeta")) + return OSTREE_OBJECT_TYPE_DIR_META; + else if (!strcmp (str, "commit")) + return OSTREE_OBJECT_TYPE_COMMIT; + else if (!strcmp (str, "tombstone-commit")) + return OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT; + else if (!strcmp (str, "commitmeta")) + return OSTREE_OBJECT_TYPE_COMMIT_META; + else if (!strcmp (str, "payload-link")) + return OSTREE_OBJECT_TYPE_PAYLOAD_LINK; + g_assert_not_reached (); + return 0; +} + +/** + * ostree_object_to_string: + * @checksum: An ASCII checksum + * @objtype: Object type + * + * Returns: A string containing both @checksum and a stringifed version of @objtype + */ +char * +ostree_object_to_string (const char *checksum, + OstreeObjectType objtype) +{ + return g_strconcat (checksum, ".", ostree_object_type_to_string (objtype), NULL); +} + +/** + * ostree_object_from_string: + * @str: An ASCII checksum + * @out_checksum: (out) (transfer full): Parsed checksum + * @out_objtype: (out): Parsed object type + * + * Reverse ostree_object_to_string(). + */ +void +ostree_object_from_string (const char *str, + gchar **out_checksum, + OstreeObjectType *out_objtype) +{ + const char *dot; + + dot = strrchr (str, '.'); + g_assert (dot != NULL); + *out_checksum = g_strndup (str, dot - str); + *out_objtype = ostree_object_type_from_string (dot + 1); +} + +/** + * ostree_hash_object_name: + * @a: A #GVariant containing a serialized object + * + * Use this function with #GHashTable and ostree_object_name_serialize(). + */ +guint +ostree_hash_object_name (gconstpointer a) +{ + GVariant *variant = (gpointer)a; + const char *checksum; + OstreeObjectType objtype; + gint objtype_int; + + ostree_object_name_deserialize (variant, &checksum, &objtype); + objtype_int = (gint) objtype; + return g_str_hash (checksum) + g_int_hash (&objtype_int); +} + +/** + * ostree_cmp_checksum_bytes: + * @a: A binary checksum + * @b: A binary checksum + * + * Compare two binary checksums, using memcmp(). + */ +int +ostree_cmp_checksum_bytes (const guchar *a, + const guchar *b) +{ + return memcmp (a, b, OSTREE_SHA256_DIGEST_LEN); +} + +/** + * ostree_object_name_serialize: + * @checksum: An ASCII checksum + * @objtype: An object type + * + * Returns: (transfer floating): A new floating #GVariant containing checksum string and objtype + */ +GVariant * +ostree_object_name_serialize (const char *checksum, + OstreeObjectType objtype) +{ + g_assert (objtype >= OSTREE_OBJECT_TYPE_FILE + && objtype <= OSTREE_OBJECT_TYPE_LAST); + return g_variant_new ("(su)", checksum, (guint32)objtype); +} + +/** + * ostree_object_name_deserialize: + * @variant: A #GVariant of type (su) + * @out_checksum: (out) (transfer none): Pointer into string memory of @variant with checksum + * @out_objtype: (out): Return object type + * + * Reverse ostree_object_name_serialize(). Note that @out_checksum is + * only valid for the lifetime of @variant, and must not be freed. + */ +void +ostree_object_name_deserialize (GVariant *variant, + const char **out_checksum, + OstreeObjectType *out_objtype) +{ + guint32 objtype_u32; + g_variant_get (variant, "(&su)", out_checksum, &objtype_u32); + *out_objtype = (OstreeObjectType)objtype_u32; +} + +/** + * ostree_checksum_b64_inplace_to_bytes: (skip) + * @checksum: (array fixed-size=32): An binary checksum of length 32 + * @buf: Output location, must be at least 45 bytes in length + * + * Overwrite the contents of @buf with stringified version of @csum. + */ +void +ostree_checksum_b64_inplace_to_bytes (const char *checksum, + guchar *buf) +{ + int state = 0; + guint save = 0; + char tmpbuf[44]; + int i; + + for (i = 0; i < 43; i++) + { + char c = checksum[i]; + if (c == '_') + tmpbuf[i] = '/'; + else + tmpbuf[i] = c; + } + tmpbuf[43] = '='; + + g_base64_decode_step (tmpbuf, sizeof (tmpbuf), (guchar *) buf, &state, &save); +} + +/** + * ostree_checksum_inplace_to_bytes: + * @checksum: a SHA256 string + * @buf: Output buffer with at least 32 bytes of space + * + * Convert @checksum from a string to binary in-place, without + * allocating memory. Use this function in hot code paths. + */ +void +ostree_checksum_inplace_to_bytes (const char *checksum, + guchar *buf) +{ + guint i; + guint j; + + for (i = 0, j = 0; i < OSTREE_SHA256_DIGEST_LEN; i += 1, j += 2) + { + gint big, little; + + g_assert (checksum[j]); + g_assert (checksum[j+1]); + + big = g_ascii_xdigit_value (checksum[j]); + little = g_ascii_xdigit_value (checksum[j+1]); + + g_assert (big != -1); + g_assert (little != -1); + + buf[i] = (big << 4) | little; + } +} + +/** + * ostree_checksum_to_bytes: + * @checksum: An ASCII checksum + * + * Returns: (transfer full) (array fixed-size=32): Binary checksum from @checksum of length 32; free with g_free(). + */ +guchar * +ostree_checksum_to_bytes (const char *checksum) +{ + guchar *ret = g_malloc (OSTREE_SHA256_DIGEST_LEN); + ostree_checksum_inplace_to_bytes (checksum, ret); + return ret; +} + +/** + * ostree_checksum_to_bytes_v: + * @checksum: An ASCII checksum + * + * Returns: (transfer full): New #GVariant of type ay with length 32 + */ +GVariant * +ostree_checksum_to_bytes_v (const char *checksum) +{ + guchar result[OSTREE_SHA256_DIGEST_LEN]; + ostree_checksum_inplace_to_bytes (checksum, result); + return ot_gvariant_new_bytearray ((guchar*)result, OSTREE_SHA256_DIGEST_LEN); +} + +/** + * ostree_checksum_b64_to_bytes: + * @checksum: An ASCII checksum + * + * Returns: (transfer full) (array fixed-size=32): Binary version of @checksum. + * + * Since: 2016.8 + */ +guchar * +ostree_checksum_b64_to_bytes (const char *checksum) +{ + guchar *ret = g_malloc (32); + ostree_checksum_b64_inplace_to_bytes (checksum, ret); + return ret; +} + +/** + * ostree_checksum_inplace_from_bytes: (skip) + * @csum: (array fixed-size=32): An binary checksum of length 32 + * @buf: Output location, must be at least OSTREE_SHA256_STRING_LEN+1 bytes in length + * + * Overwrite the contents of @buf with stringified version of @csum. + */ +void +ostree_checksum_inplace_from_bytes (const guchar *csum, + char *buf) +{ + ot_bin2hex (buf, csum, OSTREE_SHA256_DIGEST_LEN); +} + +/** + * ostree_checksum_b64_inplace_from_bytes: (skip) + * @csum: (array fixed-size=32): An binary checksum of length 32 + * @buf: Output location, must be at least 44 bytes in length + * + * Overwrite the contents of @buf with modified base64 encoding of @csum. + * The "modified" term refers to the fact that instead of '/', the '_' + * character is used. + */ +void +ostree_checksum_b64_inplace_from_bytes (const guchar *csum, + char *buf) +{ + char tmpbuf[44]; + int save = 0; + int state = 0; + gsize outlen; + int i; + + /* At some point, we can optimize this, but for now it's + * a lot easier to reuse GLib's base64 encoder and postprocess it + * to replace the '/' with '_'. + */ + outlen = g_base64_encode_step (csum, OSTREE_SHA256_DIGEST_LEN, FALSE, tmpbuf, &state, &save); + outlen += g_base64_encode_close (FALSE, tmpbuf+outlen, &state, &save); + g_assert (outlen == 44); + + for (i = 0; i < sizeof (tmpbuf); i++) + { + char c = tmpbuf[i]; + if (c == '=') + { + g_assert (i == 43); + buf[i] = '\0'; + } + else if (c == '/') + buf[i] = '_'; + else + buf[i] = c; + } +} + +/** + * ostree_checksum_from_bytes: + * @csum: (array fixed-size=32): An binary checksum of length 32 + * + * Returns: (transfer full): String form of @csum + */ +char * +ostree_checksum_from_bytes (const guchar *csum) +{ + char *ret = g_malloc (OSTREE_SHA256_STRING_LEN+1); + ostree_checksum_inplace_from_bytes (csum, ret); + return ret; +} + +/** + * ostree_checksum_from_bytes_v: + * @csum_v: #GVariant of type ay + * + * Returns: (transfer full): String form of @csum_bytes + */ +char * +ostree_checksum_from_bytes_v (GVariant *csum_v) +{ + return ostree_checksum_from_bytes (ostree_checksum_bytes_peek (csum_v)); +} + +/** + * ostree_checksum_b64_from_bytes: + * @csum: (array fixed-size=32): An binary checksum of length 32 + * + * Returns: (transfer full): Modified base64 encoding of @csum + * + * The "modified" term refers to the fact that instead of '/', the '_' + * character is used. + * + * Since: 2016.8 + */ +char * +ostree_checksum_b64_from_bytes (const guchar *csum) +{ + char *ret = g_malloc (44); + ostree_checksum_b64_inplace_from_bytes (csum, ret); + return ret; +} + +/** + * ostree_checksum_bytes_peek: + * @bytes: #GVariant of type ay + * + * Returns: (transfer none) (array fixed-size=32) (element-type guint8): Binary checksum data in @bytes; do not free. If @bytes does not have the correct length, return %NULL. + */ +const guchar * +ostree_checksum_bytes_peek (GVariant *bytes) +{ + gsize n_elts; + const guchar *ret; + ret = g_variant_get_fixed_array (bytes, &n_elts, 1); + if (G_UNLIKELY (n_elts != OSTREE_SHA256_DIGEST_LEN)) + return NULL; + return ret; +} + +/** + * ostree_checksum_bytes_peek_validate: + * @bytes: #GVariant of type ay + * @error: Errror + * + * Like ostree_checksum_bytes_peek(), but also throws @error. + * + * Returns: (transfer none) (array fixed-size=32) (element-type guint8): Binary checksum data + */ +const guchar * +ostree_checksum_bytes_peek_validate (GVariant *bytes, + GError **error) +{ + const guchar *ret = ostree_checksum_bytes_peek (bytes); + if (G_UNLIKELY (!ret)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid checksum of length %" G_GUINT64_FORMAT + " expected 32", (guint64) g_variant_n_children (bytes)); + return NULL; + } + return ret; +} + +/* + * _ostree_loose_path: + * @buf: Output buffer, must be _OSTREE_LOOSE_PATH_MAX in size + * @checksum: ASCII checksum + * @objtype: Object type + * @mode: Repository mode + * + * Overwrite the contents of @buf with relative path for loose + * object. + */ +void +_ostree_loose_path (char *buf, + const char *checksum, + OstreeObjectType objtype, + OstreeRepoMode mode) +{ + *buf = checksum[0]; + buf++; + *buf = checksum[1]; + buf++; + snprintf (buf, _OSTREE_LOOSE_PATH_MAX - 2, "/%s.%s%s", + checksum + 2, ostree_object_type_to_string (objtype), + (!OSTREE_OBJECT_TYPE_IS_META (objtype) && mode == OSTREE_REPO_MODE_ARCHIVE) ? "z" : ""); +} + +/** + * _ostree_stbuf_to_gfileinfo: + * @mode: File mode + * @uid: File uid + * @gid: File gid + * + * OSTree only stores a subset of file attributes; for example, + * timestamps are intentionally not stored. This function creates a + * #GFileInfo based on the attributes of a `struct stat` that match + * those file attributes. + * + * Returns: (transfer full): A new #GFileInfo mapping a subset of @stbuf. + */ +GFileInfo * +_ostree_stbuf_to_gfileinfo (const struct stat *stbuf) +{ + GFileInfo *ret = g_file_info_new (); + GFileType ftype; + const mode_t mode = stbuf->st_mode; + if (S_ISDIR (mode)) + ftype = G_FILE_TYPE_DIRECTORY; + else if (S_ISREG (mode)) + ftype = G_FILE_TYPE_REGULAR; + else if (S_ISLNK (mode)) + ftype = G_FILE_TYPE_SYMBOLIC_LINK; + else if (S_ISBLK (mode) || S_ISCHR(mode) || S_ISFIFO(mode)) + ftype = G_FILE_TYPE_SPECIAL; + else + ftype = G_FILE_TYPE_UNKNOWN; + g_file_info_set_attribute_uint32 (ret, "standard::type", ftype); + g_file_info_set_attribute_boolean (ret, "standard::is-symlink", S_ISLNK (mode)); + g_file_info_set_attribute_uint32 (ret, "unix::uid", stbuf->st_uid); + g_file_info_set_attribute_uint32 (ret, "unix::gid", stbuf->st_gid); + g_file_info_set_attribute_uint32 (ret, "unix::mode", mode); + + /* those aren't stored by ostree, but used by the devino cache */ + g_file_info_set_attribute_uint32 (ret, "unix::device", stbuf->st_dev); + g_file_info_set_attribute_uint64 (ret, "unix::inode", stbuf->st_ino); + + if (S_ISREG (mode)) + g_file_info_set_attribute_uint64 (ret, "standard::size", stbuf->st_size); + + return ret; +} + +/** + * _ostree_gfileinfo_to_stbuf: + * @file_info: File info + * @out_stbuf: (out): stat buffer + * + * Map GFileInfo data from @file_info onto @out_stbuf. + */ +void +_ostree_gfileinfo_to_stbuf (GFileInfo *file_info, + struct stat *out_stbuf) +{ + struct stat stbuf = {0,}; + stbuf.st_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + stbuf.st_uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid"); + stbuf.st_gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid"); + if (S_ISREG (stbuf.st_mode)) + stbuf.st_size = g_file_info_get_attribute_uint64 (file_info, "standard::size"); + *out_stbuf = stbuf; +} + +/** + * _ostree_gfileinfo_equal: + * @a: First file info + * @b: Second file info + * + * OSTree only cares about a subset of file attributes. This function + * checks whether two #GFileInfo objects are equal as far as OSTree is + * concerned. + * + * Returns: TRUE if the #GFileInfo objects are OSTree-equivalent. + */ +gboolean +_ostree_gfileinfo_equal (GFileInfo *a, GFileInfo *b) +{ + /* trivial case */ + if (a == b) + return TRUE; + +#define CHECK_ONE_ATTR(type, attr, a, b) \ + do { if (g_file_info_get_attribute_##type(a, attr) != \ + g_file_info_get_attribute_##type(b, attr)) \ + return FALSE; \ + } while (0) + + CHECK_ONE_ATTR (uint32, "unix::uid", a, b); + CHECK_ONE_ATTR (uint32, "unix::gid", a, b); + CHECK_ONE_ATTR (uint32, "unix::mode", a, b); + CHECK_ONE_ATTR (uint32, "standard::type", a, b); + CHECK_ONE_ATTR (uint64, "standard::size", a, b); + +#undef CHECK_ONE_ATTR + + return TRUE; +} + +/* Same motives as _ostree_gfileinfo_equal(), but for stat structs. */ +gboolean +_ostree_stbuf_equal (struct stat *stbuf_a, struct stat *stbuf_b) +{ + /* trivial case */ + if (stbuf_a == stbuf_b) + return TRUE; + if (stbuf_a->st_mode != stbuf_b->st_mode) + return FALSE; + if (S_ISREG (stbuf_a->st_mode) && (stbuf_a->st_size != stbuf_b->st_size)) + return FALSE; + if (stbuf_a->st_uid != stbuf_b->st_uid) + return FALSE; + if (stbuf_a->st_gid != stbuf_b->st_gid) + return FALSE; + return TRUE; +} + +/* Many parts of libostree only care about mode,uid,gid - this creates + * a new GFileInfo with those fields see. + */ +GFileInfo * +_ostree_mode_uidgid_to_gfileinfo (mode_t mode, uid_t uid, gid_t gid) +{ + struct stat stbuf = { 0, }; + stbuf.st_mode = mode; + stbuf.st_uid = uid; + stbuf.st_gid = gid; + return _ostree_stbuf_to_gfileinfo (&stbuf); +} + +/* + * _ostree_get_relative_object_path: + * @checksum: ASCII checksum string + * @type: Object type + * @compressed: Whether or not the repository object is compressed + * + * Returns: (transfer full): Relative path for a loose object + */ +char * +_ostree_get_relative_object_path (const char *checksum, + OstreeObjectType type, + gboolean compressed) +{ + GString *path; + + g_assert (strlen (checksum) == OSTREE_SHA256_STRING_LEN); + + path = g_string_new ("objects/"); + + g_string_append_len (path, checksum, 2); + g_string_append_c (path, '/'); + g_string_append (path, checksum + 2); + g_string_append_c (path, '.'); + g_string_append (path, ostree_object_type_to_string (type)); + if (!OSTREE_OBJECT_TYPE_IS_META (type) && compressed) + g_string_append (path, "z"); + + return g_string_free (path, FALSE); +} + +char * +_ostree_get_relative_static_delta_path (const char *from, + const char *to, + const char *target) +{ + guint8 csum_to[OSTREE_SHA256_DIGEST_LEN]; + char to_b64[44]; + guint8 csum_to_copy[OSTREE_SHA256_DIGEST_LEN]; + GString *ret = g_string_new ("deltas/"); + + ostree_checksum_inplace_to_bytes (to, csum_to); + ostree_checksum_b64_inplace_from_bytes (csum_to, to_b64); + ostree_checksum_b64_inplace_to_bytes (to_b64, csum_to_copy); + + g_assert (memcmp (csum_to, csum_to_copy, OSTREE_SHA256_DIGEST_LEN) == 0); + + if (from != NULL) + { + guint8 csum_from[OSTREE_SHA256_DIGEST_LEN]; + char from_b64[44]; + + ostree_checksum_inplace_to_bytes (from, csum_from); + ostree_checksum_b64_inplace_from_bytes (csum_from, from_b64); + + g_string_append_c (ret, from_b64[0]); + g_string_append_c (ret, from_b64[1]); + g_string_append_c (ret, '/'); + g_string_append (ret, from_b64 + 2); + g_string_append_c (ret, '-'); + } + + g_string_append_c (ret, to_b64[0]); + g_string_append_c (ret, to_b64[1]); + if (from == NULL) + g_string_append_c (ret, '/'); + g_string_append (ret, to_b64 + 2); + + if (target != NULL) + { + g_string_append_c (ret, '/'); + g_string_append (ret, target); + } + + return g_string_free (ret, FALSE); +} + +char * +_ostree_get_relative_static_delta_superblock_path (const char *from, + const char *to) +{ + return _ostree_get_relative_static_delta_path (from, to, "superblock"); +} + +char * +_ostree_get_relative_static_delta_detachedmeta_path (const char *from, + const char *to) +{ + return _ostree_get_relative_static_delta_path (from, to, "meta"); +} + +char * +_ostree_get_relative_static_delta_part_path (const char *from, + const char *to, + guint i) +{ + g_autofree char *partstr = g_strdup_printf ("%u", i); + return _ostree_get_relative_static_delta_path (from, to, partstr); +} + +gboolean +_ostree_parse_delta_name (const char *delta_name, + char **out_from, + char **out_to, + GError **error) +{ + g_auto(GStrv) parts = NULL; + g_return_val_if_fail (delta_name != NULL, FALSE); + + parts = g_strsplit (delta_name, "-", 2); + + /* NB: if delta_name is "", parts[0] is NULL, but the error + * validate_checksum_string() gives for "" is nice enough, + * so we just coerce it here */ + if (!ostree_validate_checksum_string (parts[0] ?: "", error)) + return FALSE; + + if (parts[0] && parts[1] && + !ostree_validate_checksum_string (parts[1], error)) + return FALSE; + + *out_from = *out_to = NULL; + if (parts[0] && parts[1]) + { + ot_transfer_out_value (out_from, &parts[0]); + ot_transfer_out_value (out_to, &parts[1]); + } + else + { + ot_transfer_out_value (out_to, &parts[0]); + } + + return TRUE; +} + +/* + * file_header_parse: + * @metadata: A metadata variant of type %OSTREE_FILE_HEADER_GVARIANT_FORMAT + * @out_file_info: (out): Parsed file information + * @out_xattrs: (out): Parsed extended attribute set + * @error: Error + * + * Load file header information into standard Gio #GFileInfo object, + * along with extended attributes tored in @out_xattrs. + */ +static gboolean +file_header_parse (GVariant *metadata, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GError **error) +{ + guint32 uid, gid, mode, rdev; + const char *symlink_target; + g_autoptr(GVariant) ret_xattrs = NULL; + + g_variant_get (metadata, "(uuuu&s@a(ayay))", + &uid, &gid, &mode, &rdev, + &symlink_target, &ret_xattrs); + if (rdev != 0) + return glnx_throw (error, "Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev)); + + uid = GUINT32_FROM_BE (uid); + gid = GUINT32_FROM_BE (gid); + mode = GUINT32_FROM_BE (mode); + g_autoptr(GFileInfo) ret_file_info = _ostree_mode_uidgid_to_gfileinfo (mode, uid, gid); + + if (S_ISREG (mode)) + { + ; + } + else if (S_ISLNK (mode)) + { + g_file_info_set_attribute_byte_string (ret_file_info, "standard::symlink-target", symlink_target); + } + else + { + return glnx_throw (error, "Corrupted archive file; invalid mode %u", mode); + } + + ot_transfer_out_value(out_file_info, &ret_file_info); + ot_transfer_out_value(out_xattrs, &ret_xattrs); + return TRUE; +} + +/* + * zlib_file_header_parse: + * @metadata: A metadata variant of type %OSTREE_FILE_HEADER_GVARIANT_FORMAT + * @out_file_info: (out): Parsed file information + * @out_xattrs: (out): Parsed extended attribute set + * @error: Error + * + * Like ostree_file_header_parse(), but operates on zlib-compressed + * content. + */ +static gboolean +zlib_file_header_parse (GVariant *metadata, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GError **error) +{ + guint64 size; + guint32 uid, gid, mode, rdev; + const char *symlink_target; + g_autoptr(GVariant) ret_xattrs = NULL; + + g_variant_get (metadata, "(tuuuu&s@a(ayay))", &size, + &uid, &gid, &mode, &rdev, + &symlink_target, &ret_xattrs); + if (rdev != 0) + return glnx_throw (error, "Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev)); + + uid = GUINT32_FROM_BE (uid); + gid = GUINT32_FROM_BE (gid); + mode = GUINT32_FROM_BE (mode); + g_autoptr(GFileInfo) ret_file_info = _ostree_mode_uidgid_to_gfileinfo (mode, uid, gid); + g_file_info_set_size (ret_file_info, GUINT64_FROM_BE (size)); + + if (S_ISREG (mode)) + { + ; + } + else if (S_ISLNK (mode)) + { + g_file_info_set_attribute_byte_string (ret_file_info, "standard::symlink-target", symlink_target); + } + else + { + return glnx_throw (error, "Corrupted archive file; invalid mode %u", mode); + } + + ot_transfer_out_value(out_file_info, &ret_file_info); + ot_transfer_out_value(out_xattrs, &ret_xattrs); + return TRUE; +} + +/** + * ostree_validate_structureof_objtype: + * @objtype: + * @error: Error + * + * Returns: %TRUE if @objtype represents a valid object type + */ +gboolean +ostree_validate_structureof_objtype (guchar objtype, + GError **error) +{ + OstreeObjectType objtype_v = (OstreeObjectType) objtype; + if (objtype_v < OSTREE_OBJECT_TYPE_FILE + || objtype_v > OSTREE_OBJECT_TYPE_COMMIT) + return glnx_throw (error, "Invalid object type '%u'", objtype); + return TRUE; +} + +/** + * ostree_validate_structureof_csum_v: + * @checksum: a #GVariant of type "ay" + * @error: Error + * + * Returns: %TRUE if @checksum is a valid binary SHA256 checksum + */ +gboolean +ostree_validate_structureof_csum_v (GVariant *checksum, + GError **error) +{ + return ostree_checksum_bytes_peek_validate (checksum, error) != NULL; +} + +/** + * ostree_validate_structureof_checksum_string: + * @checksum: an ASCII string + * @error: Error + * + * Returns: %TRUE if @checksum is a valid ASCII SHA256 checksum + */ +gboolean +ostree_validate_structureof_checksum_string (const char *checksum, + GError **error) +{ + int i = 0; + size_t len = strlen (checksum); + + if (len != OSTREE_SHA256_STRING_LEN) + { + /* If we happen to get e.g. an Apache directory listing HTML, don't + * dump it all to the error. + * https://github.com/projectatomic/rpm-ostree/issues/885 + */ + g_autofree char *sanitized = quash_string_for_error_message (checksum, len, + OSTREE_SHA256_STRING_LEN); + return glnx_throw (error, "Invalid rev %s", sanitized); + } + + for (i = 0; i < len; i++) + { + guint8 c = ((guint8*) checksum)[i]; + + if (!((c >= 48 && c <= 57) + || (c >= 97 && c <= 102))) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid character '%d' in rev '%s'", + c, checksum); + return FALSE; + } + } + return TRUE; +} + +static gboolean +validate_variant (GVariant *variant, + const GVariantType *variant_type, + GError **error) +{ + if (!g_variant_is_normal_form (variant)) + { + return glnx_throw (error, "%s", "Not normal form"); + } + if (!g_variant_is_of_type (variant, variant_type)) + { + return glnx_throw (error, "Doesn't match variant type '%s'", + (char *)variant_type); + } + return TRUE; +} + +/* TODO: make this public later; just wraps the previously public + * commit/dirtree/dirmeta verifiers. + */ +gboolean +_ostree_validate_structureof_metadata (OstreeObjectType objtype, + GVariant *metadata, + GError **error) +{ + g_assert (OSTREE_OBJECT_TYPE_IS_META (objtype)); + + switch (objtype) + { + case OSTREE_OBJECT_TYPE_COMMIT: + if (!ostree_validate_structureof_commit (metadata, error)) + return FALSE; + break; + case OSTREE_OBJECT_TYPE_DIR_TREE: + if (!ostree_validate_structureof_dirtree (metadata, error)) + return FALSE; + break; + case OSTREE_OBJECT_TYPE_DIR_META: + if (!ostree_validate_structureof_dirmeta (metadata, error)) + return FALSE; + break; + case OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT: + case OSTREE_OBJECT_TYPE_COMMIT_META: + case OSTREE_OBJECT_TYPE_PAYLOAD_LINK: + /* TODO */ + break; + case OSTREE_OBJECT_TYPE_FILE: + g_assert_not_reached (); + break; + } + + return TRUE; +} + +/* Used by fsck as well as pull. Verify the checksum of a metadata object + * and its "structure" or the additional schema we impose on GVariants such + * as ensuring the "ay" checksum entries are of length 32. Another important + * one is checking for path traversal in dirtree objects. + */ +gboolean +_ostree_verify_metadata_object (OstreeObjectType objtype, + const char *expected_checksum, + GVariant *metadata, + GError **error) +{ + g_assert (expected_checksum); + + g_auto(OtChecksum) hasher = { 0, }; + ot_checksum_init (&hasher); + ot_checksum_update (&hasher, g_variant_get_data (metadata), g_variant_get_size (metadata)); + + char actual_checksum[OSTREE_SHA256_STRING_LEN+1]; + ot_checksum_get_hexdigest (&hasher, actual_checksum, sizeof (actual_checksum)); + if (!_ostree_compare_object_checksum (objtype, expected_checksum, actual_checksum, error)) + return FALSE; + + /* Add the checksum + objtype prefix here */ + { const char *error_prefix = glnx_strjoina (expected_checksum, ".", ostree_object_type_to_string (objtype)); + GLNX_AUTO_PREFIX_ERROR(error_prefix, error); + if (!_ostree_validate_structureof_metadata (objtype, metadata, error)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_validate_structureof_commit: + * @commit: A commit object, %OSTREE_OBJECT_TYPE_COMMIT + * @error: Error + * + * Use this to validate the basic structure of @commit, independent of + * any other objects it references. + * + * Returns: %TRUE if @commit is structurally valid + */ +gboolean +ostree_validate_structureof_commit (GVariant *commit, + GError **error) +{ + if (!validate_variant (commit, OSTREE_COMMIT_GVARIANT_FORMAT, error)) + return FALSE; + + g_autoptr(GVariant) parent_csum_v = NULL; + g_variant_get_child (commit, 1, "@ay", &parent_csum_v); + gsize n_elts; + (void) g_variant_get_fixed_array (parent_csum_v, &n_elts, 1); + if (n_elts > 0) + { + if (!ostree_validate_structureof_csum_v (parent_csum_v, error)) + return FALSE; + } + + g_autoptr(GVariant) content_csum_v = NULL; + g_variant_get_child (commit, 6, "@ay", &content_csum_v); + if (!ostree_validate_structureof_csum_v (content_csum_v, error)) + return FALSE; + + g_autoptr(GVariant) metadata_csum_v = NULL; + g_variant_get_child (commit, 7, "@ay", &metadata_csum_v); + if (!ostree_validate_structureof_csum_v (metadata_csum_v, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_validate_structureof_dirtree: + * @dirtree: A dirtree object, %OSTREE_OBJECT_TYPE_DIR_TREE + * @error: Error + * + * Use this to validate the basic structure of @dirtree, independent of + * any other objects it references. + * + * Returns: %TRUE if @dirtree is structurally valid + */ +gboolean +ostree_validate_structureof_dirtree (GVariant *dirtree, + GError **error) +{ + const char *filename; + g_autoptr(GVariant) content_csum_v = NULL; + g_autoptr(GVariant) meta_csum_v = NULL; + g_autoptr(GVariantIter) contents_iter = NULL; + + if (!validate_variant (dirtree, OSTREE_TREE_GVARIANT_FORMAT, error)) + return FALSE; + + g_variant_get_child (dirtree, 0, "a(say)", &contents_iter); + + while (g_variant_iter_loop (contents_iter, "(&s@ay)", + &filename, &content_csum_v)) + { + if (!ot_util_filename_validate (filename, error)) + return FALSE; + if (!ostree_validate_structureof_csum_v (content_csum_v, error)) + return FALSE; + } + /* Note we only use autoptr in case we broke out of the loop early; + * g_variant_iter_loop() has special semantics. + */ + content_csum_v = NULL; + + g_variant_iter_free (contents_iter); + g_variant_get_child (dirtree, 1, "a(sayay)", &contents_iter); + + while (g_variant_iter_loop (contents_iter, "(&s@ay@ay)", + &filename, &content_csum_v, &meta_csum_v)) + { + if (!ot_util_filename_validate (filename, error)) + return FALSE; + if (!ostree_validate_structureof_csum_v (content_csum_v, error)) + return FALSE; + if (!ostree_validate_structureof_csum_v (meta_csum_v, error)) + return FALSE; + } + content_csum_v = NULL; + meta_csum_v = NULL; + + return TRUE; +} + +/* This bit mirrors similar code in commit_loose_regfile_object() for the + * bare-user-only mode. It's opt-in though for all pulls. + */ +gboolean +_ostree_validate_bareuseronly_mode (guint32 content_mode, + const char *checksum, + GError **error) +{ + if (S_ISREG (content_mode)) + { + const guint32 invalid_modebits = ((content_mode & ~S_IFMT) & ~0775); + if (invalid_modebits > 0) + return glnx_throw (error, "Content object %s: invalid mode 0%04o with bits 0%04o", + checksum, content_mode, invalid_modebits); + } + else if (S_ISLNK (content_mode)) + ; /* Nothing */ + else + g_assert_not_reached (); + + return TRUE; +} + +static gboolean +validate_stat_mode_perms (guint32 mode, + GError **error) +{ + guint32 otherbits = (~S_IFMT & ~S_IRWXU & ~S_IRWXG & ~S_IRWXO & + ~S_ISUID & ~S_ISGID & ~S_ISVTX); + + if (mode & otherbits) + return glnx_throw (error, "Invalid mode %u; invalid bits in mode", mode); + + return TRUE; +} + +/** + * ostree_validate_structureof_file_mode: + * @mode: A Unix filesystem mode + * @error: Error + * + * Returns: %TRUE if @mode represents a valid file type and permissions + */ +gboolean +ostree_validate_structureof_file_mode (guint32 mode, + GError **error) +{ + if (!(S_ISREG (mode) || S_ISLNK (mode))) + return glnx_throw (error, "Invalid file metadata mode %u; not a valid file type", mode); + + if (!validate_stat_mode_perms (mode, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_validate_structureof_dirmeta: + * @dirmeta: A dirmeta object, %OSTREE_OBJECT_TYPE_DIR_META + * @error: Error + * + * Use this to validate the basic structure of @dirmeta. + * + * Returns: %TRUE if @dirmeta is structurally valid + */ +gboolean +ostree_validate_structureof_dirmeta (GVariant *dirmeta, + GError **error) +{ + guint32 mode; + + if (!validate_variant (dirmeta, OSTREE_DIRMETA_GVARIANT_FORMAT, error)) + return FALSE; + + g_variant_get_child (dirmeta, 2, "u", &mode); + mode = GUINT32_FROM_BE (mode); + + if (!S_ISDIR (mode)) + return glnx_throw (error, "Invalid directory metadata mode %u; not a directory", mode); + + if (!validate_stat_mode_perms (mode, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_commit_get_parent: + * @commit_variant: Variant of type %OSTREE_OBJECT_TYPE_COMMIT + * + * Returns: Checksum of the parent commit of @commit_variant, or %NULL + * if none + */ +gchar * +ostree_commit_get_parent (GVariant *commit_variant) +{ + g_autoptr(GVariant) bytes = NULL; + bytes = g_variant_get_child_value (commit_variant, 1); + if (g_variant_n_children (bytes) == 0) + return NULL; + return ostree_checksum_from_bytes_v (bytes); +} + +/** + * ostree_commit_get_timestamp: + * @commit_variant: Commit object + * + * Returns: timestamp in seconds since the Unix epoch, UTC + * Since: 2016.3 + */ +guint64 +ostree_commit_get_timestamp (GVariant *commit_variant) +{ + guint64 ret; + g_variant_get_child (commit_variant, 5, "t", &ret); + return GUINT64_FROM_BE (ret); +} + + +/** + * ostree_commit_get_content_checksum: + * @commit_variant: A commit object + * + * There are use cases where one wants a checksum just of the content of a + * commit. OSTree commits by default capture the current timestamp, and may have + * additional metadata, which means that re-committing identical content + * often results in a new checksum. + * + * By comparing checksums of content, it's possible to easily distinguish + * cases where nothing actually changed. + * + * The content checksums is simply defined as `SHA256(root dirtree_checksum || root_dirmeta_checksum)`, + * i.e. the SHA-256 of the root "dirtree" object's checksum concatenated with the + * root "dirmeta" checksum (both in binary form, not hexadecimal). + * + * Returns: (nullable): A SHA-256 hex string, or %NULL if @commit_variant is not well-formed + * + * Since: 2018.2 + */ +gchar * +ostree_commit_get_content_checksum (GVariant *commit_variant) +{ + g_auto(OtChecksum) checksum = { 0, }; + ot_checksum_init (&checksum); + + g_autoptr(GVariant) tree_contents_csum = NULL; + g_autoptr(GVariant) tree_meta_csum = NULL; + + g_variant_get_child (commit_variant, 6, "@ay", &tree_contents_csum); + g_variant_get_child (commit_variant, 7, "@ay", &tree_meta_csum); + + const guchar *bytes; + bytes = ostree_checksum_bytes_peek_validate (tree_contents_csum, NULL); + if (!bytes) + return NULL; + ot_checksum_update (&checksum, bytes, OSTREE_SHA256_DIGEST_LEN); + bytes = ostree_checksum_bytes_peek_validate (tree_meta_csum, NULL); + if (!bytes) + return NULL; + ot_checksum_update (&checksum, bytes, OSTREE_SHA256_DIGEST_LEN); + char hexdigest[OSTREE_SHA256_STRING_LEN+1]; + ot_checksum_get_hexdigest (&checksum, hexdigest, sizeof (hexdigest)); + return g_strdup (hexdigest); +} + +G_DEFINE_BOXED_TYPE (OstreeCommitSizesEntry, ostree_commit_sizes_entry, + ostree_commit_sizes_entry_copy, ostree_commit_sizes_entry_free) + +/** + * ostree_commit_sizes_entry_new: + * @checksum: (not nullable): object checksum + * @objtype: object type + * @unpacked: unpacked object size + * @archived: compressed object size + * + * Create a new #OstreeCommitSizesEntry for representing an object in a + * commit's "ostree.sizes" metadata. + * + * Returns: (transfer full) (nullable): a new #OstreeCommitSizesEntry + * Since: 2020.1 + */ +OstreeCommitSizesEntry * +ostree_commit_sizes_entry_new (const gchar *checksum, + OstreeObjectType objtype, + guint64 unpacked, + guint64 archived) +{ + g_return_val_if_fail (checksum == NULL || ostree_validate_checksum_string (checksum, NULL), NULL); + + g_autoptr(OstreeCommitSizesEntry) entry = g_new0 (OstreeCommitSizesEntry, 1); + entry->checksum = g_strdup (checksum); + entry->objtype = objtype; + entry->unpacked = unpacked; + entry->archived = archived; + + return g_steal_pointer (&entry); +} + +/** + * ostree_commit_sizes_entry_copy: + * @entry: (not nullable): an #OstreeCommitSizesEntry + * + * Create a copy of the given @entry. + * + * Returns: (transfer full) (nullable): a new copy of @entry + * Since: 2020.1 + */ +OstreeCommitSizesEntry * +ostree_commit_sizes_entry_copy (const OstreeCommitSizesEntry *entry) +{ + g_return_val_if_fail (entry != NULL, NULL); + + return ostree_commit_sizes_entry_new (entry->checksum, + entry->objtype, + entry->unpacked, + entry->archived); +} + +/** + * ostree_commit_sizes_entry_free: + * @entry: (transfer full): an #OstreeCommitSizesEntry + * + * Free given @entry. + * + * Since: 2020.1 + */ +void +ostree_commit_sizes_entry_free (OstreeCommitSizesEntry *entry) +{ + g_return_if_fail (entry != NULL); + + g_free (entry->checksum); + g_free (entry); +} + +static gboolean +read_sizes_entry (GVariant *entry, + OstreeCommitSizesEntry **out_sizes, + GError **error) +{ + gsize entry_size = g_variant_get_size (entry); + g_return_val_if_fail (entry_size >= OSTREE_SHA256_DIGEST_LEN + 2, FALSE); + + const guchar *buffer = g_variant_get_data (entry); + if (buffer == NULL) + return glnx_throw (error, "Could not read ostree.sizes metadata entry"); + + char checksum[OSTREE_SHA256_STRING_LEN + 1]; + ostree_checksum_inplace_from_bytes (buffer, checksum); + buffer += OSTREE_SHA256_DIGEST_LEN; + entry_size -= OSTREE_SHA256_DIGEST_LEN; + + gsize bytes_read = 0; + guint64 archived = 0; + if (!_ostree_read_varuint64 (buffer, entry_size, &archived, &bytes_read)) + return glnx_throw (error, "Unexpected EOF reading ostree.sizes varint"); + buffer += bytes_read; + entry_size -= bytes_read; + + guint64 unpacked = 0; + if (!_ostree_read_varuint64 (buffer, entry_size, &unpacked, &bytes_read)) + return glnx_throw (error, "Unexpected EOF reading ostree.sizes varint"); + buffer += bytes_read; + entry_size -= bytes_read; + + /* On newer commits, an additional byte is used for the object type. */ + OstreeObjectType objtype; + if (entry_size > 0) + { + objtype = *buffer; + if (objtype < OSTREE_OBJECT_TYPE_FILE || objtype > OSTREE_OBJECT_TYPE_LAST) + return glnx_throw (error, "Unexpected ostree.sizes object type %u", + objtype); + buffer++; + entry_size--; + } + else + { + /* Assume the object is a file. */ + objtype = OSTREE_OBJECT_TYPE_FILE; + } + + g_autoptr(OstreeCommitSizesEntry) sizes = ostree_commit_sizes_entry_new (checksum, + objtype, + unpacked, + archived); + + if (out_sizes != NULL) + *out_sizes = g_steal_pointer (&sizes); + + return TRUE; +} + +/** + * ostree_commit_get_object_sizes: + * @commit_variant: (not nullable): variant of type %OSTREE_OBJECT_TYPE_COMMIT + * @out_sizes_entries: (out) (element-type OstreeCommitSizesEntry) (transfer container) (optional): + * return location for an array of object size entries + * @error: Error + * + * Reads a commit's "ostree.sizes" metadata and returns an array of + * #OstreeCommitSizesEntry in @out_sizes_entries. Each element + * represents an object in the commit. If the commit does not contain + * the "ostree.sizes" metadata, a %G_IO_ERROR_NOT_FOUND error will be + * returned. + * + * Since: 2020.1 + */ +gboolean +ostree_commit_get_object_sizes (GVariant *commit_variant, + GPtrArray **out_sizes_entries, + GError **error) +{ + g_return_val_if_fail (commit_variant != NULL, FALSE); + + g_autoptr(GVariant) metadata = g_variant_get_child_value (commit_variant, 0); + g_autoptr(GVariant) sizes_variant = + g_variant_lookup_value (metadata, "ostree.sizes", + G_VARIANT_TYPE ("a" _OSTREE_OBJECT_SIZES_ENTRY_SIGNATURE)); + if (sizes_variant == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No metadata key ostree.sizes in commit"); + return FALSE; + } + + g_autoptr(GPtrArray) sizes_entries = + g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_commit_sizes_entry_free); + g_autoptr(GVariant) entry = NULL; + GVariantIter entry_iter; + g_variant_iter_init (&entry_iter, sizes_variant); + while ((entry = g_variant_iter_next_value (&entry_iter))) + { + OstreeCommitSizesEntry *sizes_entry = NULL; + if (!read_sizes_entry (entry, &sizes_entry, error)) + return FALSE; + g_clear_pointer (&entry, g_variant_unref); + g_ptr_array_add (sizes_entries, sizes_entry); + } + + if (out_sizes_entries != NULL) + *out_sizes_entries = g_steal_pointer (&sizes_entries); + + return TRUE; +} + +/* Used in pull/deploy to validate we're not being downgraded */ +gboolean +_ostree_compare_timestamps (const char *current_rev, + guint64 current_ts, + const char *new_rev, + guint64 new_ts, + GError **error) +{ + /* Newer timestamp is OK */ + if (new_ts > current_ts) + return TRUE; + /* If they're equal, ensure they're the same rev */ + if (new_ts == current_ts || strcmp (current_rev, new_rev) == 0) + return TRUE; + + /* Looks like a downgrade, format an error message */ + g_autoptr(GDateTime) current_dt = g_date_time_new_from_unix_utc (current_ts); + g_autoptr(GDateTime) new_dt = g_date_time_new_from_unix_utc (new_ts); + + if (current_dt == NULL || new_dt == NULL) + return glnx_throw (error, "Upgrade target revision '%s' timestamp (%" G_GINT64_FORMAT ") or current revision '%s' timestamp (%" G_GINT64_FORMAT ") is invalid", + new_rev, new_ts, + current_rev, current_ts); + + g_autofree char *current_ts_str = g_date_time_format (current_dt, "%c"); + g_autofree char *new_ts_str = g_date_time_format (new_dt, "%c"); + + return glnx_throw (error, "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit", + new_rev, new_ts_str, current_rev, current_ts_str); +} + + +#ifndef OSTREE_DISABLE_GPGME +GVariant * +_ostree_detached_metadata_append_gpg_sig (GVariant *existing_metadata, + GBytes *signature_bytes) +{ + GVariantDict metadata_dict; + g_autoptr(GVariant) signature_data = NULL; + g_autoptr(GVariantBuilder) signature_builder = NULL; + + g_variant_dict_init (&metadata_dict, existing_metadata); + + signature_data = g_variant_dict_lookup_value (&metadata_dict, + _OSTREE_METADATA_GPGSIGS_NAME, + _OSTREE_METADATA_GPGSIGS_TYPE); + + /* signature_data may be NULL */ + signature_builder = ot_util_variant_builder_from_variant (signature_data, _OSTREE_METADATA_GPGSIGS_TYPE); + + g_variant_builder_add (signature_builder, "@ay", ot_gvariant_new_ay_bytes (signature_bytes)); + + g_variant_dict_insert_value (&metadata_dict, + _OSTREE_METADATA_GPGSIGS_NAME, + g_variant_builder_end (signature_builder)); + + return g_variant_dict_end (&metadata_dict); +} +#endif /* OSTREE_DISABLE_GPGME */ + +/** + * _ostree_get_default_sysroot_path: + * + * Returns a #GFile for the default system root, which is usually the root + * directory ("/") unless overridden by the %OSTREE_SYSROOT environment + * variable. + * + * Returns: a #GFile for the default system root + */ +GFile * +_ostree_get_default_sysroot_path (void) +{ + static gsize default_sysroot_path_initialized; + static GFile *default_sysroot_path; + + if (g_once_init_enter (&default_sysroot_path_initialized)) + { + const char *path = g_getenv ("OSTREE_SYSROOT"); + if (path == NULL || *path == '\0') + path = "/"; + default_sysroot_path = g_file_new_for_path (path); + g_once_init_leave (&default_sysroot_path_initialized, 1); + } + + return default_sysroot_path; +} + +/** + * ostree_check_version: + * @required_year: Major/year required + * @required_release: Release version required + * + * Returns: %TRUE if current libostree has at least the requested version, %FALSE otherwise + * + * Since: 2017.4 + */ +gboolean +ostree_check_version (guint required_year, guint required_release) +{ + return OSTREE_CHECK_VERSION(required_year, required_release); +} diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h new file mode 100644 index 0000000..3b903d5 --- /dev/null +++ b/src/libostree/ostree-core.h @@ -0,0 +1,577 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include +#include +#include + +G_BEGIN_DECLS + +/** + * OSTREE_MAX_METADATA_SIZE: + * + * Default limit for maximum permitted size in bytes of metadata objects fetched + * over HTTP (including repo/config files, refs, and commit/dirtree/dirmeta + * objects). This is an arbitrary number intended to mitigate disk space + * exhaustion attacks. + */ +#define OSTREE_MAX_METADATA_SIZE (10 * 1024 * 1024) + +/** + * OSTREE_MAX_METADATA_WARN_SIZE: + * + * This variable is no longer meaningful, it is kept only for compatibility. + */ +#define OSTREE_MAX_METADATA_WARN_SIZE (7 * 1024 * 1024) + +/** + * OSTREE_SHA256_DIGEST_LEN: + * + * Length of a sha256 digest when expressed as raw bytes + */ +#define OSTREE_SHA256_DIGEST_LEN (32) + +/** + * OSTREE_SHA256_STRING_LEN: + * + * Length of a sha256 digest when expressed as a hexadecimal string + */ +#define OSTREE_SHA256_STRING_LEN (64) + +/** + * OstreeObjectType: + * @OSTREE_OBJECT_TYPE_FILE: Content; regular file, symbolic link + * @OSTREE_OBJECT_TYPE_DIR_TREE: List of children (trees or files), and metadata + * @OSTREE_OBJECT_TYPE_DIR_META: Directory metadata + * @OSTREE_OBJECT_TYPE_COMMIT: Toplevel object, refers to tree and dirmeta for root + * @OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT: Toplevel object, refers to a deleted commit + * @OSTREE_OBJECT_TYPE_COMMIT_META: Detached metadata for a commit + * @OSTREE_OBJECT_TYPE_PAYLOAD_LINK: Symlink to a .file given its checksum on the payload only. + * + * Enumeration for core object types; %OSTREE_OBJECT_TYPE_FILE is for + * content, the other types are metadata. + */ +typedef enum { + OSTREE_OBJECT_TYPE_FILE = 1, /* .file */ + OSTREE_OBJECT_TYPE_DIR_TREE = 2, /* .dirtree */ + OSTREE_OBJECT_TYPE_DIR_META = 3, /* .dirmeta */ + OSTREE_OBJECT_TYPE_COMMIT = 4, /* .commit */ + OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT = 5, /* .commit-tombstone */ + OSTREE_OBJECT_TYPE_COMMIT_META = 6, /* .commitmeta */ + OSTREE_OBJECT_TYPE_PAYLOAD_LINK = 7, /* .payload-link */ +} OstreeObjectType; + +/** + * OSTREE_OBJECT_TYPE_IS_META: + * @t: An #OstreeObjectType + * + * Returns: %TRUE if object type is metadata + */ +#define OSTREE_OBJECT_TYPE_IS_META(t) (t >= 2 && t <= 6) + +/** + * OSTREE_OBJECT_TYPE_LAST: + * + * Last valid object type; use this to validate ranges. + */ +#define OSTREE_OBJECT_TYPE_LAST OSTREE_OBJECT_TYPE_PAYLOAD_LINK + +/** + * OSTREE_DIRMETA_GVARIANT_FORMAT: + * + * - u - uid (big-endian) + * - u - gid (big-endian) + * - u - mode (big-endian) + * - a(ayay) - xattrs + */ +#define OSTREE_DIRMETA_GVARIANT_STRING "(uuua(ayay))" +#define OSTREE_DIRMETA_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_DIRMETA_GVARIANT_STRING) + +/** + * OSTREE_FILEMETA_GVARIANT_FORMAT: + * + * This is not a regular object type, but used as an xattr on a .file object + * in bare-user repositories. This allows us to store metadata information that we + * can't store in the real filesystem but we can still use a regular .file object + * that we can hardlink to in the case of a user-mode checkout. + * + * - u - uid (big-endian) + * - u - gid (big-endian) + * - u - mode (big-endian) + * - a(ayay) - xattrs + */ +#define OSTREE_FILEMETA_GVARIANT_STRING "(uuua(ayay))" +#define OSTREE_FILEMETA_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_FILEMETA_GVARIANT_STRING) + +/** + * OSTREE_TREE_GVARIANT_FORMAT: + * + * - a(say) - array of (filename, checksum) for files + * - a(sayay) - array of (dirname, tree_checksum, meta_checksum) for directories + */ +#define OSTREE_TREE_GVARIANT_STRING "(a(say)a(sayay))" +#define OSTREE_TREE_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_TREE_GVARIANT_STRING) + +/** + * OSTREE_COMMIT_GVARIANT_FORMAT: + * + * - a{sv} - Metadata + * - ay - parent checksum (empty string for initial) + * - a(say) - Related objects + * - s - subject + * - s - body + * - t - Timestamp in seconds since the epoch (UTC, big-endian) + * - ay - Root tree contents + * - ay - Root tree metadata + */ +#define OSTREE_COMMIT_GVARIANT_STRING "(a{sv}aya(say)sstayay)" +#define OSTREE_COMMIT_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_COMMIT_GVARIANT_STRING) + +/** + * OSTREE_SUMMARY_GVARIANT_FORMAT: + * + * - a(s(taya{sv})) - Map of ref name -> (latest commit size, latest commit checksum, additional metadata), sorted by ref name + * - a{sv} - Additional metadata, at the current time the following are defined: + * - key: "ostree.static-deltas", value: a{sv}, static delta name -> 32 bytes of checksum + * - key: "ostree.summary.last-modified", value: t, timestamp (seconds since + * the Unix epoch in UTC, big-endian) when the summary was last regenerated + * (similar to the HTTP `Last-Modified` header) + * - key: "ostree.summary.expires", value: t, timestamp (seconds since the + * Unix epoch in UTC, big-endian) after which the summary is considered + * stale and should be re-downloaded if possible (similar to the HTTP + * `Expires` header) + * + * The currently defined keys for the `a{sv}` of additional metadata for each commit are: + * - key: `ostree.commit.timestamp`, value: `t`, timestamp (seconds since the + * Unix epoch in UTC, big-endian) when the commit was committed + */ +#define OSTREE_SUMMARY_GVARIANT_STRING "(a(s(taya{sv}))a{sv})" +#define OSTREE_SUMMARY_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_SUMMARY_GVARIANT_STRING) + +#define OSTREE_SUMMARY_SIG_GVARIANT_STRING "a{sv}" +#define OSTREE_SUMMARY_SIG_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_SUMMARY_SIG_GVARIANT_STRING) + +/** + * OSTREE_TIMESTAMP: + * + * The mtime used for stored files. This was originally 0, changed to 1 for + * a few releases, then was reverted due to regressions it introduced from + * users who had been using zero before. + */ +#define OSTREE_TIMESTAMP (0) + +/** + * OstreeRepoMode: + * @OSTREE_REPO_MODE_BARE: Files are stored as themselves; checkouts are hardlinks; can only be written as root + * @OSTREE_REPO_MODE_ARCHIVE: Files are compressed, should be owned by non-root. Can be served via HTTP. Since: 2017.12 + * @OSTREE_REPO_MODE_ARCHIVE_Z2: Legacy alias for `OSTREE_REPO_MODE_ARCHIVE` + * @OSTREE_REPO_MODE_BARE_USER: Files are stored as themselves, except ownership; can be written by user. Hardlinks work only in user checkouts. + * @OSTREE_REPO_MODE_BARE_USER_ONLY: Same as BARE_USER, but all metadata is not stored, so it can only be used for user checkouts. Does not need xattrs. + * + * See the documentation of #OstreeRepo for more information about the + * possible modes. + */ +typedef enum { + OSTREE_REPO_MODE_BARE, + OSTREE_REPO_MODE_ARCHIVE, + OSTREE_REPO_MODE_ARCHIVE_Z2 = OSTREE_REPO_MODE_ARCHIVE, + OSTREE_REPO_MODE_BARE_USER, + OSTREE_REPO_MODE_BARE_USER_ONLY, +} OstreeRepoMode; + +/** + * OSTREE_COMMIT_META_KEY_VERSION: + * + * GVariant type `s`. This metadata key is used for version numbers. A freeform + * string; the intention is that systems using ostree do not interpret this + * semantically as traditional package managers do. + * + * This is the only ostree-defined metadata key that does not start with `ostree.`. + * Since: 2014.9 + */ +#define OSTREE_COMMIT_META_KEY_VERSION "version" + +/** + * OSTREE_COMMIT_META_KEY_ARCHITECTURE: + * + * GVariant type `s`. Intended to describe the CPU architecture. This is a freeform string, and some distributions + * which have existing package managers might want to match that schema. If you + * don't have a prior schema, it's recommended to use `uname -m` by default (i.e. the Linux kernel schema). In the future + * ostree might include a builtin function to compare architectures. + * + * Since: 2020.4 + */ +#define OSTREE_COMMIT_META_KEY_ARCHITECTURE "ostree.architecture" + +/** + * OSTREE_COMMIT_META_KEY_ENDOFLIFE_REBASE: + * + * GVariant type `s`. Should contain a refspec defining a new target branch; + * `ostree admin upgrade` and `OstreeSysrootUpgrader` will automatically initiate + * a rebase upon encountering this metadata key. + * + * Since: 2017.7 + */ +#define OSTREE_COMMIT_META_KEY_ENDOFLIFE_REBASE "ostree.endoflife-rebase" +/** + * OSTREE_COMMIT_META_KEY_ENDOFLIFE: + * + * GVariant type `s`. This metadata key is used to display vendor's message + * when an update stream for a particular branch ends. It usually provides + * update instructions for the users. + * + * Since: 2017.7 + */ +#define OSTREE_COMMIT_META_KEY_ENDOFLIFE "ostree.endoflife" +/** + * OSTREE_COMMIT_META_KEY_SOURCE_TITLE: + * + * GVariant type `s`. This should hold a relatively short single line value + * containing a human-readable "source" for a commit, intended to be displayed + * near the origin ref. This is particularly useful for systems that inject + * content into an OSTree commit from elsewhere - for example, generating from + * an OCI or qcow2 image. Or if generating from packages, the enabled repository + * names and their versions. + * + * Try to keep this key short (e.g. < 80 characters) and human-readable; if you + * desire machine readable data, consider injecting separate metadata keys. + * + * Since: 2017.13 + */ +#define OSTREE_COMMIT_META_KEY_SOURCE_TITLE "ostree.source-title" + +/** + * OSTREE_COMMIT_META_KEY_REF_BINDING: + * + * GVariant type `as`; each element is a branch name. If this is added to a + * commit, `ostree_repo_pull()` will enforce that the commit was retrieved from + * one of the branch names in this array. This prevents "sidegrade" attacks. + * The rationale for having this support multiple branch names is that it helps + * support a "promotion" model of taking a commit and moving it between development + * and production branches. + * + * Since: 2017.9 + */ +#define OSTREE_COMMIT_META_KEY_REF_BINDING "ostree.ref-binding" +/** + * OSTREE_COMMIT_META_KEY_COLLECTION_BINDING: + * + * GVariant type `s`. If this is added to a commit, `ostree_repo_pull()` + * will enforce that the commit was retrieved from a repository which has + * the same collection ID. See `ostree_repo_set_collection_id()`. + * This is most useful in concert with `OSTREE_COMMIT_META_KEY_REF_BINDING`, + * as it more strongly binds the commit to the repository and branch. + * + * Since: 2018.6 + */ +#define OSTREE_COMMIT_META_KEY_COLLECTION_BINDING "ostree.collection-binding" + +_OSTREE_PUBLIC +const GVariantType *ostree_metadata_variant_type (OstreeObjectType objtype); + +_OSTREE_PUBLIC +gboolean ostree_validate_checksum_string (const char *sha256, + GError **error); + +_OSTREE_PUBLIC +guchar *ostree_checksum_to_bytes (const char *checksum); +_OSTREE_PUBLIC +GVariant *ostree_checksum_to_bytes_v (const char *checksum); +_OSTREE_PUBLIC +guchar *ostree_checksum_b64_to_bytes (const char *checksum); +_OSTREE_PUBLIC +void ostree_checksum_b64_inplace_to_bytes (const char *checksum, + guint8 *buf); + +_OSTREE_PUBLIC +char * ostree_checksum_from_bytes (const guchar *csum); +_OSTREE_PUBLIC +char * ostree_checksum_from_bytes_v (GVariant *csum_v); +_OSTREE_PUBLIC +char * ostree_checksum_b64_from_bytes (const guchar *csum); + +_OSTREE_PUBLIC +void ostree_checksum_inplace_from_bytes (const guchar *csum, + char *buf); +_OSTREE_PUBLIC +void ostree_checksum_b64_inplace_from_bytes (const guchar *csum, + char *buf); + +_OSTREE_PUBLIC +void ostree_checksum_inplace_to_bytes (const char *checksum, + guchar *buf); + +_OSTREE_PUBLIC +const guchar *ostree_checksum_bytes_peek (GVariant *bytes); + +_OSTREE_PUBLIC +const guchar *ostree_checksum_bytes_peek_validate (GVariant *bytes, GError **error); + +_OSTREE_PUBLIC +int ostree_cmp_checksum_bytes (const guchar *a, const guchar *b); + +_OSTREE_PUBLIC +gboolean ostree_validate_rev (const char *rev, GError **error); + +_OSTREE_PUBLIC +gboolean ostree_validate_collection_id (const char *collection_id, GError **error); + +_OSTREE_PUBLIC +gboolean ostree_validate_remote_name (const char *remote_name, GError **error); + +_OSTREE_PUBLIC +gboolean ostree_parse_refspec (const char *refspec, + char **out_remote, + char **out_ref, + GError **error); + +_OSTREE_PUBLIC +const char * ostree_object_type_to_string (OstreeObjectType objtype); + +_OSTREE_PUBLIC +OstreeObjectType ostree_object_type_from_string (const char *str); + +_OSTREE_PUBLIC +guint ostree_hash_object_name (gconstpointer a); + +_OSTREE_PUBLIC +GVariant *ostree_object_name_serialize (const char *checksum, + OstreeObjectType objtype); + +_OSTREE_PUBLIC +void ostree_object_name_deserialize (GVariant *variant, + const char **out_checksum, + OstreeObjectType *out_objtype); + +_OSTREE_PUBLIC +char * ostree_object_to_string (const char *checksum, + OstreeObjectType objtype); + +_OSTREE_PUBLIC +void ostree_object_from_string (const char *str, + gchar **out_checksum, + OstreeObjectType *out_objtype); + +_OSTREE_PUBLIC +gboolean +ostree_content_stream_parse (gboolean compressed, + GInputStream *input, + guint64 input_length, + gboolean trusted, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_content_file_parse (gboolean compressed, + GFile *content_path, + gboolean trusted, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_content_file_parse_at (gboolean compressed, + int parent_dfd, + const char *path, + gboolean trusted, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean +ostree_raw_file_to_archive_z2_stream (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream **out_input, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean +ostree_raw_file_to_archive_z2_stream_with_options (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + GVariant *options, + GInputStream **out_input, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_raw_file_to_content_stream (GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream **out_input, + guint64 *out_length, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_checksum_file_from_input (GFileInfo *file_info, + GVariant *xattrs, + GInputStream *in, + OstreeObjectType objtype, + guchar **out_csum, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_checksum_file (GFile *f, + OstreeObjectType objtype, + guchar **out_csum, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_break_hardlink (int dfd, + const char *path, + gboolean skip_xattrs, + GCancellable *cancellable, + GError **error); + +/** + * OstreeChecksumFlags: + * + * Since: 2017.13 + */ +typedef enum { + OSTREE_CHECKSUM_FLAGS_NONE = 0, + OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS = (1 << 0), +} OstreeChecksumFlags; + +_OSTREE_PUBLIC +gboolean ostree_checksum_file_at (int dfd, + const char *path, + struct stat *stbuf, + OstreeObjectType objtype, + OstreeChecksumFlags flags, + char **out_checksum, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_checksum_file_async (GFile *f, + OstreeObjectType objtype, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +_OSTREE_PUBLIC +gboolean ostree_checksum_file_async_finish (GFile *f, + GAsyncResult *result, + guchar **out_csum, + GError **error); + +_OSTREE_PUBLIC +GVariant *ostree_create_directory_metadata (GFileInfo *dir_info, + GVariant *xattrs); + +/* VALIDATION */ + +_OSTREE_PUBLIC +gboolean ostree_validate_structureof_objtype (guchar objtype, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_validate_structureof_csum_v (GVariant *checksum, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_validate_structureof_checksum_string (const char *checksum, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_validate_structureof_file_mode (guint32 mode, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_validate_structureof_commit (GVariant *commit, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_validate_structureof_dirtree (GVariant *dirtree, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_validate_structureof_dirmeta (GVariant *dirmeta, + GError **error); + +_OSTREE_PUBLIC +gchar * ostree_commit_get_parent (GVariant *commit_variant); +_OSTREE_PUBLIC +guint64 ostree_commit_get_timestamp (GVariant *commit_variant); + +_OSTREE_PUBLIC +gchar * ostree_commit_get_content_checksum (GVariant *commit_variant); + +/** + * OstreeCommitSizesEntry: + * @checksum: (not nullable): object checksum + * @objtype: object type + * @unpacked: unpacked object size + * @archived: compressed object size + * + * Structure representing an entry in the "ostree.sizes" commit metadata. Each + * entry corresponds to an object in the associated commit. + * + * Since: 2020.1 + */ +typedef struct { + gchar *checksum; + OstreeObjectType objtype; + guint64 unpacked; + guint64 archived; +} OstreeCommitSizesEntry; + +_OSTREE_PUBLIC +GType ostree_commit_sizes_entry_get_type (void); + +_OSTREE_PUBLIC +OstreeCommitSizesEntry *ostree_commit_sizes_entry_new (const gchar *checksum, + OstreeObjectType objtype, + guint64 unpacked, + guint64 archived); +_OSTREE_PUBLIC +OstreeCommitSizesEntry *ostree_commit_sizes_entry_copy (const OstreeCommitSizesEntry *entry); +_OSTREE_PUBLIC +void ostree_commit_sizes_entry_free (OstreeCommitSizesEntry *entry); + +_OSTREE_PUBLIC +gboolean ostree_commit_get_object_sizes (GVariant *commit_variant, + GPtrArray **out_sizes_entries, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_check_version (guint required_year, guint required_release); + +G_END_DECLS diff --git a/src/libostree/ostree-deployment-private.h b/src/libostree/ostree-deployment-private.h new file mode 100644 index 0000000..ad77317 --- /dev/null +++ b/src/libostree/ostree-deployment-private.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-deployment.h" + +G_BEGIN_DECLS + + +/** + * OstreeDeployment: + * @parent_instance: + * @index: Global offset + * @osname: + * @csum: OSTree checksum of tree + * @deployserial: How many times this particular csum appears in deployment list + * @bootcsum: Checksum of kernel+initramfs + * @bootserial: An integer assigned to this tree per its ${bootcsum} + * @bootconfig: Bootloader configuration + * @origin: How to construct an upgraded version of this tree + * @unlocked: The unlocked state + * @staged: TRUE iff this deployment is staged + */ +struct _OstreeDeployment +{ + GObject parent_instance; + + int index; + char *osname; + char *csum; + int deployserial; + char *bootcsum; + int bootserial; + OstreeBootconfigParser *bootconfig; + GKeyFile *origin; + OstreeDeploymentUnlockedState unlocked; + gboolean staged; +}; + +void _ostree_deployment_set_bootcsum (OstreeDeployment *self, const char *bootcsum); + +G_END_DECLS diff --git a/src/libostree/ostree-deployment.c b/src/libostree/ostree-deployment.c new file mode 100644 index 0000000..6532a97 --- /dev/null +++ b/src/libostree/ostree-deployment.c @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" +#include "ostree.h" +#include "ostree-deployment-private.h" + +typedef GObjectClass OstreeDeploymentClass; + +G_DEFINE_TYPE (OstreeDeployment, ostree_deployment, G_TYPE_OBJECT) + +const char * +ostree_deployment_get_csum (OstreeDeployment *self) +{ + return self->csum; +} + +const char * +ostree_deployment_get_bootcsum (OstreeDeployment *self) +{ + return self->bootcsum; +} + +/* + * ostree_deployment_get_osname: + * @self: Deployemnt + * + * Returns: The "stateroot" name, also known as an "osname" + */ +const char * +ostree_deployment_get_osname (OstreeDeployment *self) +{ + return self->osname; +} + +int +ostree_deployment_get_deployserial (OstreeDeployment *self) +{ + return self->deployserial; +} + +int +ostree_deployment_get_bootserial (OstreeDeployment *self) +{ + return self->bootserial; +} + +/** + * ostree_deployment_get_bootconfig: + * @self: Deployment + * + * Returns: (transfer none): Boot configuration + */ +OstreeBootconfigParser * +ostree_deployment_get_bootconfig (OstreeDeployment *self) +{ + return self->bootconfig; +} + +/** + * ostree_deployment_get_origin: + * @self: Deployment + * + * Returns: (transfer none): Origin + */ +GKeyFile * +ostree_deployment_get_origin (OstreeDeployment *self) +{ + return self->origin; +} + +int +ostree_deployment_get_index (OstreeDeployment *self) +{ + return self->index; +} + +void +ostree_deployment_set_index (OstreeDeployment *self, int index) +{ + self->index = index; +} + +void +ostree_deployment_set_bootserial (OstreeDeployment *self, int index) +{ + self->bootserial = index; +} + +void +ostree_deployment_set_bootconfig (OstreeDeployment *self, OstreeBootconfigParser *bootconfig) +{ + g_clear_object (&self->bootconfig); + if (bootconfig) + self->bootconfig = g_object_ref (bootconfig); +} + +void +ostree_deployment_set_origin (OstreeDeployment *self, GKeyFile *origin) +{ + g_clear_pointer (&self->origin, g_key_file_unref); + if (origin) + self->origin = g_key_file_ref (origin); +} + +/** + * ostree_deployment_origin_remove_transient_state: + * @origin: An origin + * + * The intention of an origin file is primarily describe the "inputs" that + * resulted in a deployment, and it's commonly used to derive the new state. For + * example, a key value (in pure libostree mode) is the "refspec". However, + * libostree (or other applications) may want to store "transient" state that + * should not be carried across upgrades. + * + * This function just removes all members of the `libostree-transient` group. + * The name of that group is available to all libostree users; best practice + * would be to prefix values underneath there with a short identifier for your + * software. + * + * Additionally, this function will remove the `origin/unlocked` and + * `origin/override-commit` members; these should be considered transient state + * that should have been under an explicit group. + * + * Since: 2018.3 + */ +void +ostree_deployment_origin_remove_transient_state (GKeyFile *origin) +{ + g_key_file_remove_group (origin, OSTREE_ORIGIN_TRANSIENT_GROUP, NULL); + g_key_file_remove_key (origin, "origin", "override-commit", NULL); + g_key_file_remove_key (origin, "origin", "unlocked", NULL); +} + +void +_ostree_deployment_set_bootcsum (OstreeDeployment *self, + const char *bootcsum) +{ + g_free (self->bootcsum); + self->bootcsum = g_strdup (bootcsum); +} + +/** + * ostree_deployment_clone: + * @self: Deployment + * + * Returns: (transfer full): New deep copy of @self + */ +OstreeDeployment * +ostree_deployment_clone (OstreeDeployment *self) +{ + g_autoptr(OstreeBootconfigParser) new_bootconfig = NULL; + OstreeDeployment *ret = ostree_deployment_new (self->index, self->osname, self->csum, + self->deployserial, + self->bootcsum, self->bootserial); + + new_bootconfig = ostree_bootconfig_parser_clone (self->bootconfig); + ostree_deployment_set_bootconfig (ret, new_bootconfig); + + if (self->origin) + { + g_autoptr(GKeyFile) new_origin = NULL; + g_autofree char *data = NULL; + gsize len; + gboolean success; + + data = g_key_file_to_data (self->origin, &len, NULL); + g_assert (data); + + new_origin = g_key_file_new (); + success = g_key_file_load_from_data (new_origin, data, len, 0, NULL); + g_assert (success); + + ostree_deployment_set_origin (ret, new_origin); + } + return ret; +} + +guint +ostree_deployment_hash (gconstpointer v) +{ + OstreeDeployment *d = (OstreeDeployment*)v; + return g_str_hash (ostree_deployment_get_osname (d)) + + g_str_hash (ostree_deployment_get_csum (d)) + + ostree_deployment_get_deployserial (d); +} + +/** + * ostree_deployment_equal: + * @ap: (type OstreeDeployment): A deployment + * @bp: (type OstreeDeployment): A deployment + * + * Returns: %TRUE if deployments have the same osname, csum, and deployserial + */ +gboolean +ostree_deployment_equal (gconstpointer ap, gconstpointer bp) +{ + OstreeDeployment *a = (OstreeDeployment*)ap; + OstreeDeployment *b = (OstreeDeployment*)bp; + + if (a == b) + return TRUE; + else if (a != NULL && b != NULL) + return g_str_equal (ostree_deployment_get_osname (a), + ostree_deployment_get_osname (b)) && + g_str_equal (ostree_deployment_get_csum (a), + ostree_deployment_get_csum (b)) && + ostree_deployment_get_deployserial (a) == ostree_deployment_get_deployserial (b); + else + return FALSE; +} + +static void +ostree_deployment_finalize (GObject *object) +{ + OstreeDeployment *self = OSTREE_DEPLOYMENT (object); + + g_free (self->osname); + g_free (self->csum); + g_free (self->bootcsum); + g_clear_object (&self->bootconfig); + g_clear_pointer (&self->origin, g_key_file_unref); + + G_OBJECT_CLASS (ostree_deployment_parent_class)->finalize (object); +} + +void +ostree_deployment_init (OstreeDeployment *self) +{ +} + +void +ostree_deployment_class_init (OstreeDeploymentClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = ostree_deployment_finalize; +} + +OstreeDeployment * +ostree_deployment_new (int index, + const char *osname, + const char *csum, + int deployserial, + const char *bootcsum, + int bootserial) +{ + OstreeDeployment *self; + + /* index may be -1 */ + g_return_val_if_fail (osname != NULL, NULL); + g_return_val_if_fail (csum != NULL, NULL); + g_return_val_if_fail (deployserial >= 0, NULL); + /* We can have "disconnected" deployments that don't have a + bootcsum/serial */ + + self = g_object_new (OSTREE_TYPE_DEPLOYMENT, NULL); + self->index = index; + self->osname = g_strdup (osname); + self->csum = g_strdup (csum); + self->deployserial = deployserial; + self->bootcsum = g_strdup (bootcsum); + self->bootserial = bootserial; + self->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_NONE; + return self; +} + +/** + * ostree_deployment_get_origin_relpath: + * @self: A deployment + * + * Note this function only returns a *relative* path - if you want to + * access, it, you must either use fd-relative api such as openat(), + * or concatenate it with the full ostree_sysroot_get_path(). + * + * Returns: (transfer full): Path to deployment root directory, relative to sysroot + */ +char * +ostree_deployment_get_origin_relpath (OstreeDeployment *self) +{ + return g_strdup_printf ("ostree/deploy/%s/deploy/%s.%d.origin", + ostree_deployment_get_osname (self), + ostree_deployment_get_csum (self), + ostree_deployment_get_deployserial (self)); +} + +/** + * ostree_deployment_unlocked_state_to_string: + * + * Since: 2016.4 + */ +const char * +ostree_deployment_unlocked_state_to_string (OstreeDeploymentUnlockedState state) +{ + switch (state) + { + case OSTREE_DEPLOYMENT_UNLOCKED_NONE: + return "none"; + case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX: + return "hotfix"; + case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT: + return "development"; + } + g_assert_not_reached (); +} + +/** + * ostree_deployment_get_unlocked: + * + * Since: 2016.4 + */ +OstreeDeploymentUnlockedState +ostree_deployment_get_unlocked (OstreeDeployment *self) +{ + return self->unlocked; +} + +/** + * ostree_deployment_is_pinned: + * @self: Deployment + * + * See ostree_sysroot_deployment_set_pinned(). + * + * Returns: `TRUE` if deployment will not be subject to GC + * Since: 2018.3 + */ +gboolean +ostree_deployment_is_pinned (OstreeDeployment *self) +{ + if (!self->origin) + return FALSE; + return g_key_file_get_boolean (self->origin, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", NULL); +} + +/** + * ostree_deployment_is_staged: + * @self: Deployment + * + * Returns: `TRUE` if deployment should be "finalized" at shutdown time + * Since: 2018.3 + */ +gboolean +ostree_deployment_is_staged (OstreeDeployment *self) +{ + return self->staged; +} diff --git a/src/libostree/ostree-deployment.h b/src/libostree/ostree-deployment.h new file mode 100644 index 0000000..756e39d --- /dev/null +++ b/src/libostree/ostree-deployment.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-bootconfig-parser.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_DEPLOYMENT (ostree_deployment_get_type ()) +#define OSTREE_DEPLOYMENT(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_DEPLOYMENT, OstreeDeployment)) +#define OSTREE_IS_DEPLOYMENT(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_DEPLOYMENT)) + +/** + * OSTREE_ORIGIN_TRANSIENT_GROUP: + * + * The name of a `GKeyFile` group for data that should not + * be carried across upgrades. For more information, + * see ostree_deployment_origin_remove_transient_state(). + * + * Since: 2018.3 + */ +#define OSTREE_ORIGIN_TRANSIENT_GROUP "libostree-transient" + +typedef struct _OstreeDeployment OstreeDeployment; + +_OSTREE_PUBLIC +GType ostree_deployment_get_type (void) G_GNUC_CONST; + +_OSTREE_PUBLIC +guint ostree_deployment_hash (gconstpointer v); +_OSTREE_PUBLIC +gboolean ostree_deployment_equal (gconstpointer ap, gconstpointer bp); + +_OSTREE_PUBLIC +OstreeDeployment * ostree_deployment_new (int index, + const char *osname, + const char *csum, + int deployserial, + const char *bootcsum, + int bootserial); + +_OSTREE_PUBLIC +int ostree_deployment_get_index (OstreeDeployment *self); +_OSTREE_PUBLIC +const char *ostree_deployment_get_osname (OstreeDeployment *self); +_OSTREE_PUBLIC +int ostree_deployment_get_deployserial (OstreeDeployment *self); +_OSTREE_PUBLIC +const char *ostree_deployment_get_csum (OstreeDeployment *self); +_OSTREE_PUBLIC +const char *ostree_deployment_get_bootcsum (OstreeDeployment *self); +_OSTREE_PUBLIC +int ostree_deployment_get_bootserial (OstreeDeployment *self); +_OSTREE_PUBLIC +OstreeBootconfigParser *ostree_deployment_get_bootconfig (OstreeDeployment *self); +_OSTREE_PUBLIC +GKeyFile *ostree_deployment_get_origin (OstreeDeployment *self); + +_OSTREE_PUBLIC +gboolean ostree_deployment_is_staged (OstreeDeployment *self); +_OSTREE_PUBLIC +gboolean ostree_deployment_is_pinned (OstreeDeployment *self); + +_OSTREE_PUBLIC +void ostree_deployment_set_index (OstreeDeployment *self, int index); +_OSTREE_PUBLIC +void ostree_deployment_set_bootserial (OstreeDeployment *self, int index); +_OSTREE_PUBLIC +void ostree_deployment_set_bootconfig (OstreeDeployment *self, OstreeBootconfigParser *bootconfig); +_OSTREE_PUBLIC +void ostree_deployment_set_origin (OstreeDeployment *self, GKeyFile *origin); + +_OSTREE_PUBLIC +void ostree_deployment_origin_remove_transient_state (GKeyFile *origin); + +_OSTREE_PUBLIC +OstreeDeployment *ostree_deployment_clone (OstreeDeployment *self); + +_OSTREE_PUBLIC +char *ostree_deployment_get_origin_relpath (OstreeDeployment *self); + +typedef enum { + OSTREE_DEPLOYMENT_UNLOCKED_NONE, + OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT, + OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX +} OstreeDeploymentUnlockedState; + +_OSTREE_PUBLIC +const char *ostree_deployment_unlocked_state_to_string (OstreeDeploymentUnlockedState state); + +_OSTREE_PUBLIC +OstreeDeploymentUnlockedState ostree_deployment_get_unlocked (OstreeDeployment *self); + +G_END_DECLS diff --git a/src/libostree/ostree-diff.c b/src/libostree/ostree-diff.c new file mode 100644 index 0000000..da018db --- /dev/null +++ b/src/libostree/ostree-diff.c @@ -0,0 +1,511 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "libglnx.h" +#include "ostree.h" +#include "ostree-repo-private.h" +#include "otutil.h" + +/* See ostree-repo.c for a bit more info about these ABI checks */ +#if __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 8 && __SIZEOF_INT__ == 4 +G_STATIC_ASSERT(sizeof(OstreeDiffDirsOptions) == + sizeof(int) * 2 + + sizeof(gpointer) + + sizeof(int) * (7+6) + + sizeof(int) + /* hole */ + sizeof(gpointer) * 7); +#endif + +static gboolean +get_file_checksum (OstreeDiffFlags flags, + GFile *f, + GFileInfo *f_info, + char **out_checksum, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *ret_checksum = NULL; + + if (OSTREE_IS_REPO_FILE (f)) + { + ret_checksum = g_strdup (ostree_repo_file_get_checksum ((OstreeRepoFile*)f)); + } + else + { + g_autoptr(GVariant) xattrs = NULL; + g_autoptr(GInputStream) in = NULL; + + if (!(flags & OSTREE_DIFF_FLAGS_IGNORE_XATTRS)) + { + if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f), + &xattrs, cancellable, error)) + return FALSE; + } + + if (g_file_info_get_file_type (f_info) == G_FILE_TYPE_REGULAR) + { + in = (GInputStream*)g_file_read (f, cancellable, error); + if (!in) + return FALSE; + } + + g_autofree guchar *csum = NULL; + if (!ostree_checksum_file_from_input (f_info, xattrs, in, + OSTREE_OBJECT_TYPE_FILE, + &csum, cancellable, error)) + return FALSE; + ret_checksum = ostree_checksum_from_bytes (csum); + } + + ot_transfer_out_value(out_checksum, &ret_checksum); + return TRUE; +} + +OstreeDiffItem * +ostree_diff_item_ref (OstreeDiffItem *diffitem) +{ + g_atomic_int_inc (&diffitem->refcount); + return diffitem; +} + +void +ostree_diff_item_unref (OstreeDiffItem *diffitem) +{ + if (!g_atomic_int_dec_and_test (&diffitem->refcount)) + return; + + g_clear_object (&diffitem->src); + g_clear_object (&diffitem->target); + g_clear_object (&diffitem->src_info); + g_clear_object (&diffitem->target_info); + g_free (diffitem->src_checksum); + g_free (diffitem->target_checksum); + g_free (diffitem); +} + +G_DEFINE_BOXED_TYPE(OstreeDiffItem, ostree_diff_item, + ostree_diff_item_ref, + ostree_diff_item_unref); + +static OstreeDiffItem * +diff_item_new (GFile *a, + GFileInfo *a_info, + GFile *b, + GFileInfo *b_info, + char *checksum_a, + char *checksum_b) +{ + OstreeDiffItem *ret = g_new0 (OstreeDiffItem, 1); + ret->refcount = 1; + ret->src = a ? g_object_ref (a) : NULL; + ret->src_info = a_info ? g_object_ref (a_info) : NULL; + ret->target = b ? g_object_ref (b) : NULL; + ret->target_info = b_info ? g_object_ref (b_info) : b_info; + ret->src_checksum = g_strdup (checksum_a); + ret->target_checksum = g_strdup (checksum_b); + return ret; +} + +static gboolean +diff_files (OstreeDiffFlags flags, + GFile *a, + GFileInfo *a_info, + GFile *b, + GFileInfo *b_info, + OstreeDiffItem **out_item, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *checksum_a = NULL; + g_autofree char *checksum_b = NULL; + if (!get_file_checksum (flags, a, a_info, &checksum_a, cancellable, error)) + return FALSE; + if (!get_file_checksum (flags, b, b_info, &checksum_b, cancellable, error)) + return FALSE; + + g_autoptr(OstreeDiffItem) ret_item = NULL; + if (strcmp (checksum_a, checksum_b) != 0) + { + ret_item = diff_item_new (a, a_info, b, b_info, + checksum_a, checksum_b); + } + + ot_transfer_out_value(out_item, &ret_item); + return TRUE; +} + +static gboolean +diff_add_dir_recurse (GFile *d, + GPtrArray *added, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GFileEnumerator) dir_enum = + g_file_enumerate_children (d, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, + error); + if (!dir_enum) + return FALSE; + + while (TRUE) + { + GFileInfo *child_info; + const char *name; + + if (!g_file_enumerator_iterate (dir_enum, &child_info, NULL, + cancellable, error)) + return FALSE; + if (child_info == NULL) + break; + + name = g_file_info_get_name (child_info); + + g_autoptr(GFile) child = g_file_get_child (d, name); + g_ptr_array_add (added, g_object_ref (child)); + + if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY) + { + if (!diff_add_dir_recurse (child, added, cancellable, error)) + return FALSE; + } + } + + return TRUE; +} + +/** + * ostree_diff_dirs: + * @flags: Flags + * @a: First directory path, or %NULL + * @b: First directory path + * @modified: (element-type OstreeDiffItem): Modified files + * @removed: (element-type Gio.File): Removed files + * @added: (element-type Gio.File): Added files + * @cancellable: Cancellable + * @error: Error + * + * Compute the difference between directory @a and @b as 3 separate + * sets of #OstreeDiffItem in @modified, @removed, and @added. + */ +gboolean +ostree_diff_dirs (OstreeDiffFlags flags, + GFile *a, + GFile *b, + GPtrArray *modified, + GPtrArray *removed, + GPtrArray *added, + GCancellable *cancellable, + GError **error) +{ + return ostree_diff_dirs_with_options (flags, a, b, modified, + removed, added, NULL, + cancellable, error); +} + +/** + * ostree_diff_dirs_with_options: + * @flags: Flags + * @a: First directory path, or %NULL + * @b: First directory path + * @modified: (element-type OstreeDiffItem): Modified files + * @removed: (element-type Gio.File): Removed files + * @added: (element-type Gio.File): Added files + * @cancellable: Cancellable + * @options: (allow-none): Options + * @error: Error + * + * Compute the difference between directory @a and @b as 3 separate + * sets of #OstreeDiffItem in @modified, @removed, and @added. + * + * Since: 2017.4 + */ +gboolean +ostree_diff_dirs_with_options (OstreeDiffFlags flags, + GFile *a, + GFile *b, + GPtrArray *modified, + GPtrArray *removed, + GPtrArray *added, + OstreeDiffDirsOptions *options, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GError *temp_error = NULL; + g_autoptr(GFileEnumerator) dir_enum = NULL; + g_autoptr(GFile) child_a = NULL; + g_autoptr(GFile) child_b = NULL; + g_autoptr(GFileInfo) child_a_info = NULL; + g_autoptr(GFileInfo) child_b_info = NULL; + OstreeDiffDirsOptions default_opts = OSTREE_DIFF_DIRS_OPTIONS_INIT; + + if (!options) + options = &default_opts; + + /* If we're diffing versus a repo, and either of them have xattrs disabled, + * then disable for both. + */ + OstreeRepo *repo; + if (OSTREE_IS_REPO_FILE (a)) + repo = ostree_repo_file_get_repo ((OstreeRepoFile*)a); + else if (OSTREE_IS_REPO_FILE (b)) + repo = ostree_repo_file_get_repo ((OstreeRepoFile*)b); + else + repo = NULL; + if (repo != NULL && repo->disable_xattrs) + flags |= OSTREE_DIFF_FLAGS_IGNORE_XATTRS; + + if (a == NULL) + { + if (!diff_add_dir_recurse (b, added, cancellable, error)) + goto out; + + ret = TRUE; + goto out; + } + + child_a_info = g_file_query_info (a, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!child_a_info) + goto out; + + child_b_info = g_file_query_info (b, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!child_b_info) + goto out; + + /* Fast path test for unmodified directories */ + if (g_file_info_get_file_type (child_a_info) == G_FILE_TYPE_DIRECTORY + && g_file_info_get_file_type (child_b_info) == G_FILE_TYPE_DIRECTORY + && OSTREE_IS_REPO_FILE (a) + && OSTREE_IS_REPO_FILE (b)) + { + OstreeRepoFile *a_repof = (OstreeRepoFile*) a; + OstreeRepoFile *b_repof = (OstreeRepoFile*) b; + + if (strcmp (ostree_repo_file_tree_get_contents_checksum (a_repof), + ostree_repo_file_tree_get_contents_checksum (b_repof)) == 0) + { + ret = TRUE; + goto out; + } + } + + g_clear_object (&child_a_info); + g_clear_object (&child_b_info); + + dir_enum = g_file_enumerate_children (a, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!dir_enum) + goto out; + + while ((child_a_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL) + { + const char *name; + GFileType child_a_type; + GFileType child_b_type; + + name = g_file_info_get_name (child_a_info); + + g_clear_object (&child_a); + child_a = g_file_get_child (a, name); + child_a_type = g_file_info_get_file_type (child_a_info); + + g_clear_object (&child_b); + child_b = g_file_get_child (b, name); + + g_clear_object (&child_b_info); + child_b_info = g_file_query_info (child_b, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, + &temp_error); + if (!child_b_info) + { + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&temp_error); + g_ptr_array_add (removed, g_object_ref (child_a)); + } + else + { + g_propagate_error (error, temp_error); + goto out; + } + } + else + { + if (options->owner_uid >= 0) + g_file_info_set_attribute_uint32 (child_b_info, "unix::uid", options->owner_uid); + if (options->owner_gid >= 0) + g_file_info_set_attribute_uint32 (child_b_info, "unix::gid", options->owner_gid); + + child_b_type = g_file_info_get_file_type (child_b_info); + if (child_a_type != child_b_type) + { + OstreeDiffItem *diff_item = diff_item_new (child_a, child_a_info, + child_b, child_b_info, NULL, NULL); + + g_ptr_array_add (modified, diff_item); + } + else + { + OstreeDiffItem *diff_item = NULL; + + if (!diff_files (flags, child_a, child_a_info, child_b, child_b_info, &diff_item, + cancellable, error)) + goto out; + + if (diff_item) + g_ptr_array_add (modified, diff_item); /* Transfer ownership */ + + if (child_a_type == G_FILE_TYPE_DIRECTORY) + { + if (!ostree_diff_dirs_with_options (flags, child_a, child_b, modified, + removed, added, options, + cancellable, error)) + goto out; + } + } + } + + g_clear_object (&child_a_info); + } + if (temp_error != NULL) + { + g_propagate_error (error, temp_error); + goto out; + } + + g_clear_object (&dir_enum); + dir_enum = g_file_enumerate_children (b, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!dir_enum) + goto out; + + g_clear_object (&child_b_info); + while ((child_b_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL) + { + const char *name; + + name = g_file_info_get_name (child_b_info); + + g_clear_object (&child_a); + child_a = g_file_get_child (a, name); + + g_clear_object (&child_b); + child_b = g_file_get_child (b, name); + + g_clear_object (&child_a_info); + child_a_info = g_file_query_info (child_a, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, + &temp_error); + if (!child_a_info) + { + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&temp_error); + g_ptr_array_add (added, g_object_ref (child_b)); + if (g_file_info_get_file_type (child_b_info) == G_FILE_TYPE_DIRECTORY) + { + if (!diff_add_dir_recurse (child_b, added, cancellable, error)) + goto out; + } + } + else + { + g_propagate_error (error, temp_error); + goto out; + } + } + g_clear_object (&child_b_info); + } + if (temp_error != NULL) + { + g_propagate_error (error, temp_error); + goto out; + } + + ret = TRUE; + out: + return ret; +} + +static void +print_diff_item (char prefix, + GFile *base, + GFile *file) +{ + if (g_file_is_native (file)) + { + g_autofree char *relpath = g_file_get_relative_path (base, file); + g_print ("%c %s\n", prefix, relpath); + } + else + { + g_print ("%c %s\n", prefix, gs_file_get_path_cached (file)); + } +} + +/** + * ostree_diff_print: + * @a: First directory path + * @b: First directory path + * @modified: (element-type OstreeDiffItem): Modified files + * @removed: (element-type Gio.File): Removed files + * @added: (element-type Gio.File): Added files + * + * Print the contents of a diff to stdout. + */ +void +ostree_diff_print (GFile *a, + GFile *b, + GPtrArray *modified, + GPtrArray *removed, + GPtrArray *added) +{ + guint i; + + for (i = 0; i < modified->len; i++) + { + OstreeDiffItem *diff = modified->pdata[i]; + print_diff_item ('M', a, diff->src); + } + for (i = 0; i < removed->len; i++) + { + GFile *removed_file = removed->pdata[i]; + print_diff_item ('D', a, removed_file); + } + for (i = 0; i < added->len; i++) + { + GFile *added_f = added->pdata[i]; + print_diff_item ('A', b, added_f); + } +} diff --git a/src/libostree/ostree-diff.h b/src/libostree/ostree-diff.h new file mode 100644 index 0000000..1c0024a --- /dev/null +++ b/src/libostree/ostree-diff.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include "ostree-core.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +/** + * OstreeDiffFlags: + */ +typedef enum { + OSTREE_DIFF_FLAGS_NONE = 0, + OSTREE_DIFF_FLAGS_IGNORE_XATTRS = (1 << 0) +} OstreeDiffFlags; + +/** + * OstreeDiffItem: + */ +typedef struct _OstreeDiffItem OstreeDiffItem; +struct _OstreeDiffItem +{ + volatile gint refcount; + + GFile *src; + GFile *target; + + GFileInfo *src_info; + GFileInfo *target_info; + + char *src_checksum; + char *target_checksum; +}; + +_OSTREE_PUBLIC +OstreeDiffItem *ostree_diff_item_ref (OstreeDiffItem *diffitem); +_OSTREE_PUBLIC +void ostree_diff_item_unref (OstreeDiffItem *diffitem); + +_OSTREE_PUBLIC +GType ostree_diff_item_get_type (void); + +_OSTREE_PUBLIC +gboolean ostree_diff_dirs (OstreeDiffFlags flags, + GFile *a, + GFile *b, + GPtrArray *modified, + GPtrArray *removed, + GPtrArray *added, + GCancellable *cancellable, + GError **error); + +/** + * OstreeDiffDirsOptions: + * + * An extensible options structure controlling diff dirs. Make sure + * that owner_uid/gid is set to -1 when not used. This is used by + * ostree_diff_dirs_with_options(). + */ +typedef struct { + gint owner_uid; + gint owner_gid; + + OstreeRepoDevInoCache *devino_to_csum_cache; + + gboolean unused_bools[7]; + int unused_ints[6]; + /* 4 byte hole on 64 bit */ + gpointer unused_ptrs[7]; +} OstreeDiffDirsOptions; + +/** + * OSTREE_DIFF_DIRS_OPTIONS_INIT: + * + * Use this to initialize an `OstreeDiffDirsOptions` structure. + */ +#define OSTREE_DIFF_DIRS_OPTIONS_INIT { .owner_uid = -1, .owner_gid = -1, } + +_OSTREE_PUBLIC +gboolean ostree_diff_dirs_with_options (OstreeDiffFlags flags, + GFile *a, + GFile *b, + GPtrArray *modified, + GPtrArray *removed, + GPtrArray *added, + OstreeDiffDirsOptions *options, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_diff_print (GFile *a, + GFile *b, + GPtrArray *modified, + GPtrArray *removed, + GPtrArray *added); + +G_END_DECLS diff --git a/src/libostree/ostree-dummy-enumtypes.c b/src/libostree/ostree-dummy-enumtypes.c new file mode 100644 index 0000000..dfb9d79 --- /dev/null +++ b/src/libostree/ostree-dummy-enumtypes.c @@ -0,0 +1,33 @@ +/* This file declares a stub function that is only exported + * to pacify ABI checkers - no one could really have used it. + * + * Copyright (C) 2016 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "ostree-dummy-enumtypes.h" + +/* Exported for backwards compat - see + * https://bugzilla.gnome.org/show_bug.cgi?id=764131 + */ +GType +ostree_fetcher_config_flags_get_type (void) +{ + return G_TYPE_INVALID; +} diff --git a/src/libostree/ostree-dummy-enumtypes.h b/src/libostree/ostree-dummy-enumtypes.h new file mode 100644 index 0000000..5de454c --- /dev/null +++ b/src/libostree/ostree-dummy-enumtypes.h @@ -0,0 +1,31 @@ +/* This file declares a stub function that is only exported + * to pacify ABI checkers - no one could really have used it. + * + * Copyright (C) 2016 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +#ifndef __GI_SCANNER__ +_OSTREE_PUBLIC GType +ostree_fetcher_config_flags_get_type (void); +#endif diff --git a/src/libostree/ostree-enumtypes.c.template b/src/libostree/ostree-enumtypes.c.template new file mode 100644 index 0000000..751c458 --- /dev/null +++ b/src/libostree/ostree-enumtypes.c.template @@ -0,0 +1,66 @@ +/*** BEGIN file-header ***/ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include + +#include "ostree-enumtypes.h" + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@filename@" */ +#include "@filename@" + +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType +_@enum_name@_get_type (void) +{ + static volatile gsize the_type__volatile = 0; + + if (g_once_init_enter (&the_type__volatile)) + { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, + "@VALUENAME@", + "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + + GType the_type = g_@type@_register_static ( + g_intern_static_string ("@EnumName@"), + values); + + g_once_init_leave (&the_type__volatile, the_type); + } + + return the_type__volatile; +} + +/*** END value-tail ***/ diff --git a/src/libostree/ostree-enumtypes.h.template b/src/libostree/ostree-enumtypes.h.template new file mode 100644 index 0000000..ec20fe0 --- /dev/null +++ b/src/libostree/ostree-enumtypes.h.template @@ -0,0 +1,43 @@ +/*** BEGIN file-header ***/ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +#pragma once + +#include + +G_BEGIN_DECLS + +/* Enumerations from "@filename@" */ + +/*** END file-production ***/ + +/*** BEGIN enumeration-production ***/ +#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (_@enum_name@_get_type ()) +GType _@enum_name@_get_type (void) G_GNUC_CONST; + +/*** END enumeration-production ***/ + +/*** BEGIN file-tail ***/ +G_END_DECLS + +/*** END file-tail ***/ diff --git a/src/libostree/ostree-fetcher-curl.c b/src/libostree/ostree-fetcher-curl.c new file mode 100644 index 0000000..fdf8a2e --- /dev/null +++ b/src/libostree/ostree-fetcher-curl.c @@ -0,0 +1,965 @@ +/* + * Copyright (C) 2016 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include + +/* These macros came from 7.43.0, but we want to check + * for versions a bit earlier than that (to work on CentOS 7), + * so define them here if we're using an older version. + */ +#ifndef CURL_VERSION_BITS +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#endif +#ifndef CURL_AT_LEAST_VERSION +#define CURL_AT_LEAST_VERSION(x,y,z) (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) +#endif + +/* Cargo culted from https://github.com/curl/curl/blob/curl-7_53_0/docs/examples/http2-download.c */ +#ifndef CURLPIPE_MULTIPLEX +/* This little trick will just make sure that we don't enable pipelining for + libcurls old enough to not have this symbol. It is _not_ defined to zero in + a recent libcurl header. */ +#define CURLPIPE_MULTIPLEX 0 +#endif + +#include "ostree-fetcher.h" +#include "ostree-fetcher-util.h" +#include "ostree-enumtypes.h" +#include "ostree-repo-private.h" +#include "otutil.h" + +#include "ostree-soup-uri.h" + +typedef struct FetcherRequest FetcherRequest; +typedef struct SockInfo SockInfo; + +static int sock_cb (CURL *e, curl_socket_t s, int what, void *cbp, void *sockp); +static gboolean timer_cb (gpointer data); +static void sock_unref (SockInfo *f); +static int update_timeout_cb (CURLM *multi, long timeout_ms, void *userp); +static void request_unref (FetcherRequest *req); +static void initiate_next_curl_request (FetcherRequest *req, GTask *task); +static void destroy_and_unref_source (GSource *source); + +struct OstreeFetcher +{ + GObject parent_instance; + + OstreeFetcherConfigFlags config_flags; + char *remote_name; + char *tls_ca_db_path; + char *tls_client_cert_path; + char *tls_client_key_path; + char *cookie_jar_path; + char *proxy; + struct curl_slist *extra_headers; + int tmpdir_dfd; + char *custom_user_agent; + + GMainContext *mainctx; + CURLM *multi; + GSource *timer_event; + int curl_running; + GHashTable *outstanding_requests; /* Set */ + GHashTable *sockets; /* Set */ + + guint64 bytes_transferred; +}; + +/* Information associated with a request */ +struct FetcherRequest { + guint refcount; + GPtrArray *mirrorlist; + guint idx; + + char *filename; + guint64 current_size; + guint64 max_size; + OstreeFetcherRequestFlags flags; + gboolean is_membuf; + GError *caught_write_error; + GLnxTmpfile tmpf; + GString *output_buf; + + CURL *easy; + char error[CURL_ERROR_SIZE]; + + OstreeFetcher *fetcher; +}; + +/* Information associated with a specific socket */ +struct SockInfo { + guint refcount; + curl_socket_t sockfd; + int action; + long timeout; + GSource *ch; + OstreeFetcher *fetcher; +}; + +enum { + PROP_0, + PROP_CONFIG_FLAGS +}; + +G_DEFINE_TYPE (OstreeFetcher, _ostree_fetcher, G_TYPE_OBJECT) + +static void +_ostree_fetcher_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeFetcher *self = OSTREE_FETCHER (object); + + switch (prop_id) + { + case PROP_CONFIG_FLAGS: + self->config_flags = g_value_get_flags (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +_ostree_fetcher_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeFetcher *self = OSTREE_FETCHER (object); + + switch (prop_id) + { + case PROP_CONFIG_FLAGS: + g_value_set_flags (value, self->config_flags); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +_ostree_fetcher_finalize (GObject *object) +{ + OstreeFetcher *self = OSTREE_FETCHER (object); + + curl_multi_cleanup (self->multi); + g_free (self->remote_name); + g_free (self->tls_ca_db_path); + g_free (self->tls_client_cert_path); + g_free (self->tls_client_key_path); + g_free (self->cookie_jar_path); + g_free (self->proxy); + g_assert_cmpint (g_hash_table_size (self->outstanding_requests), ==, 0); + g_clear_pointer (&self->extra_headers, (GDestroyNotify)curl_slist_free_all); + g_hash_table_unref (self->outstanding_requests); + g_hash_table_unref (self->sockets); + g_clear_pointer (&self->timer_event, (GDestroyNotify)destroy_and_unref_source); + if (self->mainctx) + g_main_context_unref (self->mainctx); + g_clear_pointer (&self->custom_user_agent, (GDestroyNotify)g_free); + + G_OBJECT_CLASS (_ostree_fetcher_parent_class)->finalize (object); +} + +static void +_ostree_fetcher_constructed (GObject *object) +{ + // OstreeFetcher *self = OSTREE_FETCHER (object); + + G_OBJECT_CLASS (_ostree_fetcher_parent_class)->constructed (object); +} + +static void +_ostree_fetcher_class_init (OstreeFetcherClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = _ostree_fetcher_set_property; + gobject_class->get_property = _ostree_fetcher_get_property; + gobject_class->finalize = _ostree_fetcher_finalize; + gobject_class->constructed = _ostree_fetcher_constructed; + + g_object_class_install_property (gobject_class, + PROP_CONFIG_FLAGS, + g_param_spec_flags ("config-flags", + "", + "", + OSTREE_TYPE_FETCHER_CONFIG_FLAGS, + OSTREE_FETCHER_FLAGS_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static void +_ostree_fetcher_init (OstreeFetcher *self) +{ + self->multi = curl_multi_init(); + self->outstanding_requests = g_hash_table_new_full (NULL, NULL, (GDestroyNotify)g_object_unref, NULL); + self->sockets = g_hash_table_new_full (NULL, NULL, (GDestroyNotify)sock_unref, NULL); + curl_multi_setopt (self->multi, CURLMOPT_SOCKETFUNCTION, sock_cb); + curl_multi_setopt (self->multi, CURLMOPT_SOCKETDATA, self); + curl_multi_setopt (self->multi, CURLMOPT_TIMERFUNCTION, update_timeout_cb); + curl_multi_setopt (self->multi, CURLMOPT_TIMERDATA, self); +#if CURL_AT_LEAST_VERSION(7, 30, 0) + /* Let's do something reasonable here. */ + curl_multi_setopt (self->multi, CURLMOPT_MAX_TOTAL_CONNECTIONS, 8); +#endif + /* This version mirrors the version at which we're enabling HTTP2 support. + * See also https://github.com/curl/curl/blob/curl-7_53_0/docs/examples/http2-download.c + */ +#if CURL_AT_LEAST_VERSION(7, 51, 0) + curl_multi_setopt (self->multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); +#endif +} + + +OstreeFetcher * +_ostree_fetcher_new (int tmpdir_dfd, + const char *remote_name, + OstreeFetcherConfigFlags flags) +{ + OstreeFetcher *fetcher = g_object_new (OSTREE_TYPE_FETCHER, "config-flags", flags, NULL); + fetcher->remote_name = g_strdup (remote_name); + fetcher->tmpdir_dfd = tmpdir_dfd; + return fetcher; +} + +static void +destroy_and_unref_source (GSource *source) +{ + g_source_destroy (source); + g_source_unref (source); +} + +static char * +request_get_uri (FetcherRequest *req, SoupURI *baseuri) +{ + if (!req->filename) + return soup_uri_to_string (baseuri, FALSE); + { g_autofree char *uristr = soup_uri_to_string (baseuri, FALSE); + return g_build_filename (uristr, req->filename, NULL); + } +} + +static gboolean +ensure_tmpfile (FetcherRequest *req, GError **error) +{ + if (!req->tmpf.initialized) + { + if (!_ostree_fetcher_tmpf_from_flags (req->flags, req->fetcher->tmpdir_dfd, + &req->tmpf, error)) + return FALSE; + } + return TRUE; +} + +/* Check for completed transfers, and remove their easy handles */ +static void +check_multi_info (OstreeFetcher *fetcher) +{ + CURLMsg *msg; + int msgs_left; + + while ((msg = curl_multi_info_read (fetcher->multi, &msgs_left)) != NULL) + { + long response; + CURL *easy = msg->easy_handle; + CURLcode curlres = msg->data.result; + GTask *task; + FetcherRequest *req; + const char *eff_url; + gboolean is_file; + gboolean continued_request = FALSE; + + if (msg->msg != CURLMSG_DONE) + continue; + + curl_easy_getinfo (easy, CURLINFO_PRIVATE, &task); + curl_easy_getinfo (easy, CURLINFO_EFFECTIVE_URL, &eff_url); + /* We should have limited the protocols; this is what + * curl's tool_operate.c does. + */ + is_file = g_str_has_prefix (eff_url, "file:"); + g_assert (is_file || g_str_has_prefix (eff_url, "http")); + + req = g_task_get_task_data (task); + + if (req->caught_write_error) + g_task_return_error (task, g_steal_pointer (&req->caught_write_error)); + else if (curlres != CURLE_OK) + { + if (is_file && curlres == CURLE_FILE_COULDNT_READ_FILE) + { + /* Handle file not found */ + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "%s", curl_easy_strerror (curlres)); + } + else + { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, + "While fetching %s: [%u] %s", eff_url, curlres, + curl_easy_strerror (curlres)); + _ostree_fetcher_journal_failure (req->fetcher->remote_name, + eff_url, curl_easy_strerror (curlres)); + } + } + else + { + curl_easy_getinfo (easy, CURLINFO_RESPONSE_CODE, &response); + if (!is_file && !(response >= 200 && response < 300)) + { + GIOErrorEnum giocode = _ostree_fetcher_http_status_code_to_io_error (response); + + if (req->idx + 1 == req->mirrorlist->len) + { + g_autofree char *msg = g_strdup_printf ("Server returned HTTP %lu", response); + g_task_return_new_error (task, G_IO_ERROR, giocode, + "%s", msg); + if (req->fetcher->remote_name && + !((req->flags & OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT) > 0 && + giocode == G_IO_ERROR_NOT_FOUND)) + _ostree_fetcher_journal_failure (req->fetcher->remote_name, + eff_url, msg); + + } + else + { + continued_request = TRUE; + } + } + else if (req->is_membuf) + { + GBytes *ret; + if ((req->flags & OSTREE_FETCHER_REQUEST_NUL_TERMINATION) > 0) + g_string_append_c (req->output_buf, '\0'); + ret = g_string_free_to_bytes (req->output_buf); + req->output_buf = NULL; + g_task_return_pointer (task, ret, (GDestroyNotify)g_bytes_unref); + } + else + { + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + + if (!ensure_tmpfile (req, error)) + { + g_task_return_error (task, g_steal_pointer (&local_error)); + } + else if (lseek (req->tmpf.fd, 0, SEEK_SET) < 0) + { + glnx_set_error_from_errno (error); + g_task_return_error (task, g_steal_pointer (&local_error)); + } + else + { + /* We return the tmpfile in the _finish wrapper */ + g_task_return_boolean (task, TRUE); + } + } + } + + curl_multi_remove_handle (fetcher->multi, easy); + if (continued_request) + { + req->idx++; + initiate_next_curl_request (req, task); + } + else + { + g_hash_table_remove (fetcher->outstanding_requests, task); + if (g_hash_table_size (fetcher->outstanding_requests) == 0) + { + g_clear_pointer (&fetcher->mainctx, g_main_context_unref); + } + } + } +} + +/* Called by glib when our timeout expires */ +static gboolean +timer_cb (gpointer data) +{ + OstreeFetcher *fetcher = data; + GSource *orig_src = fetcher->timer_event; + + (void)curl_multi_socket_action (fetcher->multi, CURL_SOCKET_TIMEOUT, 0, &fetcher->curl_running); + check_multi_info (fetcher); + if (fetcher->timer_event == orig_src) + fetcher->timer_event = NULL; + + return FALSE; +} + +/* Update the event timer after curl_multi library calls */ +static int +update_timeout_cb (CURLM *multi, long timeout_ms, void *userp) +{ + OstreeFetcher *fetcher = userp; + + g_clear_pointer (&fetcher->timer_event, (GDestroyNotify)destroy_and_unref_source); + + if (timeout_ms != -1) + { + fetcher->timer_event = g_timeout_source_new (timeout_ms); + g_source_set_callback (fetcher->timer_event, timer_cb, fetcher, NULL); + g_source_attach (fetcher->timer_event, fetcher->mainctx); + } + + return 0; +} + +/* Called by glib when we get action on a multi socket */ +static gboolean +event_cb (int fd, GIOCondition condition, gpointer data) +{ + OstreeFetcher *fetcher = data; + + int action = + (condition & G_IO_IN ? CURL_CSELECT_IN : 0) | + (condition & G_IO_OUT ? CURL_CSELECT_OUT : 0); + + (void)curl_multi_socket_action (fetcher->multi, fd, action, &fetcher->curl_running); + check_multi_info (fetcher); + if (fetcher->curl_running > 0) + { + return TRUE; + } + else + { + return FALSE; + } +} + +/* Clean up the SockInfo structure */ +static void +sock_unref (SockInfo *f) +{ + if (!f) + return; + if (--f->refcount != 0) + return; + g_clear_pointer (&f->ch, (GDestroyNotify)destroy_and_unref_source); + g_free (f); +} + +/* Assign information to a SockInfo structure */ +static void +setsock (SockInfo*f, curl_socket_t s, int act, OstreeFetcher *fetcher) +{ + GIOCondition kind = + (act&CURL_POLL_IN?G_IO_IN:0)|(act&CURL_POLL_OUT?G_IO_OUT:0); + + f->sockfd = s; + f->action = act; + g_clear_pointer (&f->ch, (GDestroyNotify)destroy_and_unref_source); + /* TODO - investigate new g_source_modify_unix_fd() so changing the poll + * flags involves less allocation. + */ + f->ch = g_unix_fd_source_new (f->sockfd, kind); + g_source_set_callback (f->ch, (GSourceFunc) event_cb, fetcher, NULL); + g_source_attach (f->ch, fetcher->mainctx); +} + +/* Initialize a new SockInfo structure */ +static void +addsock (curl_socket_t s, CURL *easy, int action, OstreeFetcher *fetcher) +{ + SockInfo *fdp = g_new0 (SockInfo, 1); + + fdp->refcount = 1; + fdp->fetcher = fetcher; + setsock (fdp, s, action, fetcher); + curl_multi_assign (fetcher->multi, s, fdp); + g_hash_table_add (fetcher->sockets, fdp); +} + +/* CURLMOPT_SOCKETFUNCTION */ +static int +sock_cb (CURL *easy, curl_socket_t s, int what, void *cbp, void *sockp) +{ + OstreeFetcher *fetcher = cbp; + SockInfo *fdp = (SockInfo*) sockp; + + if (what == CURL_POLL_REMOVE) + { + if (!g_hash_table_remove (fetcher->sockets, fdp)) + g_assert_not_reached (); + } + else + { + if (!fdp) + { + addsock (s, easy, what, fetcher); + } + else + { + setsock (fdp, s, what, fetcher); + } + } + return 0; +} + +/* CURLOPT_WRITEFUNCTION */ +static size_t +write_cb (void *ptr, size_t size, size_t nmemb, void *data) +{ + const size_t realsize = size * nmemb; + GTask *task = data; + FetcherRequest *req; + + req = g_task_get_task_data (task); + + if (req->caught_write_error) + return -1; + + if (req->max_size > 0) + { + if (realsize > req->max_size || + (realsize + req->current_size) > req->max_size) + { + const char *eff_url; + curl_easy_getinfo (req->easy, CURLINFO_EFFECTIVE_URL, &eff_url); + req->caught_write_error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, + "URI %s exceeded maximum size of %" G_GUINT64_FORMAT " bytes", + eff_url, req->max_size); + return -1; + } + } + + if (req->is_membuf) + g_string_append_len (req->output_buf, ptr, realsize); + else + { + if (!ensure_tmpfile (req, &req->caught_write_error)) + return -1; + g_assert (req->tmpf.fd >= 0); + if (glnx_loop_write (req->tmpf.fd, ptr, realsize) < 0) + { + glnx_set_error_from_errno (&req->caught_write_error); + return -1; + } + } + + req->current_size += realsize; + req->fetcher->bytes_transferred += realsize; + + return realsize; +} + +/* CURLOPT_PROGRESSFUNCTION */ +static int +prog_cb (void *p, double dltotal, double dlnow, double ult, double uln) +{ + GTask *task = p; + FetcherRequest *req; + char *eff_url; + req = g_task_get_task_data (task); + curl_easy_getinfo (req->easy, CURLINFO_EFFECTIVE_URL, &eff_url); + g_printerr ("Progress: %s (%g/%g)\n", eff_url, dlnow, dltotal); + return 0; +} + +static void +request_unref (FetcherRequest *req) +{ + if (--req->refcount != 0) + return; + + g_ptr_array_unref (req->mirrorlist); + g_free (req->filename); + g_clear_error (&req->caught_write_error); + glnx_tmpfile_clear (&req->tmpf); + if (req->output_buf) + g_string_free (req->output_buf, TRUE); + curl_easy_cleanup (req->easy); + + g_free (req); +} + +int +_ostree_fetcher_get_dfd (OstreeFetcher *fetcher) +{ + return fetcher->tmpdir_dfd; +} + +void +_ostree_fetcher_set_proxy (OstreeFetcher *self, + const char *http_proxy) +{ + g_free (self->proxy); + self->proxy = g_strdup (http_proxy); +} + +void +_ostree_fetcher_set_cookie_jar (OstreeFetcher *self, + const char *jar_path) +{ + g_free (self->cookie_jar_path); + self->cookie_jar_path = g_strdup (jar_path); +} + +void +_ostree_fetcher_set_client_cert (OstreeFetcher *self, + const char *cert_path, + const char *key_path) +{ + g_assert ((cert_path == NULL && key_path == NULL) + || (cert_path != NULL && key_path != NULL)); + g_free (self->tls_client_cert_path); + self->tls_client_cert_path = g_strdup (cert_path); + g_free (self->tls_client_key_path); + self->tls_client_key_path = g_strdup (key_path); +} + +void +_ostree_fetcher_set_tls_database (OstreeFetcher *self, + const char *dbpath) +{ + g_free (self->tls_ca_db_path); + self->tls_ca_db_path = g_strdup (dbpath); +} + +void +_ostree_fetcher_set_extra_headers (OstreeFetcher *self, + GVariant *extra_headers) +{ + GVariantIter viter; + const char *key; + const char *value; + + g_clear_pointer (&self->extra_headers, (GDestroyNotify)curl_slist_free_all); + + g_variant_iter_init (&viter, extra_headers); + while (g_variant_iter_loop (&viter, "(&s&s)", &key, &value)) + { + g_autofree char *header = g_strdup_printf ("%s: %s", key, value); + self->extra_headers = curl_slist_append (self->extra_headers, header); + } +} + +void +_ostree_fetcher_set_extra_user_agent (OstreeFetcher *self, + const char *extra_user_agent) +{ + g_clear_pointer (&self->custom_user_agent, (GDestroyNotify)g_free); + if (extra_user_agent) + { + self->custom_user_agent = + g_strdup_printf ("%s %s", OSTREE_FETCHER_USERAGENT_STRING, extra_user_agent); + } +} + +/* Re-bind all of the outstanding curl items to our new main context */ +static void +adopt_steal_mainctx (OstreeFetcher *self, + GMainContext *mainctx) +{ + g_assert (self->mainctx == NULL); + self->mainctx = mainctx; /* Transfer */ + + if (self->timer_event != NULL) + { + guint64 readytime = g_source_get_ready_time (self->timer_event); + guint64 curtime = g_source_get_time (self->timer_event); + guint64 timeout_micros = curtime - readytime; + if (curtime < readytime) + timeout_micros = 0; + update_timeout_cb (self->multi, timeout_micros / 1000, self); + } + + GLNX_HASH_TABLE_FOREACH (self->sockets, SockInfo*, fdp) + setsock (fdp, fdp->sockfd, fdp->action, self); +} + +static void +initiate_next_curl_request (FetcherRequest *req, + GTask *task) +{ + CURLcode rc; + OstreeFetcher *self = req->fetcher; + + if (req->easy) + curl_easy_cleanup (req->easy); + req->easy = curl_easy_init (); + g_assert (req->easy); + + g_assert_cmpint (req->idx, <, req->mirrorlist->len); + + SoupURI *baseuri = req->mirrorlist->pdata[req->idx]; + { g_autofree char *uri = request_get_uri (req, baseuri); + curl_easy_setopt (req->easy, CURLOPT_URL, uri); + } + + curl_easy_setopt (req->easy, CURLOPT_USERAGENT, + self->custom_user_agent ?: OSTREE_FETCHER_USERAGENT_STRING); + if (self->extra_headers) + curl_easy_setopt (req->easy, CURLOPT_HTTPHEADER, self->extra_headers); + + if (self->cookie_jar_path) + { + rc = curl_easy_setopt (req->easy, CURLOPT_COOKIEFILE, self->cookie_jar_path); + g_assert_cmpint (rc, ==, CURLM_OK); + rc = curl_easy_setopt (req->easy, CURLOPT_COOKIELIST, "RELOAD"); + g_assert_cmpint (rc, ==, CURLM_OK); + } + + if (self->proxy) + { + rc = curl_easy_setopt (req->easy, CURLOPT_PROXY, self->proxy); + g_assert_cmpint (rc, ==, CURLM_OK); + } + + if (self->tls_ca_db_path) + curl_easy_setopt (req->easy, CURLOPT_CAINFO, self->tls_ca_db_path); + + if ((self->config_flags & OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE) > 0) + curl_easy_setopt (req->easy, CURLOPT_SSL_VERIFYPEER, 0L); + + if (self->tls_client_cert_path) + { + /* Support for pkcs11: + * https://github.com/ostreedev/ostree/pull/1183 + * This will be used by https://github.com/advancedtelematic/aktualizr + * at least to fetch certificates. No test coverage at the moment + * though. See https://gitlab.com/gnutls/gnutls/tree/master/tests/pkcs11 + * and https://github.com/opendnssec/SoftHSMv2 and + * https://github.com/p11-glue/p11-kit/tree/master/p11-kit for + * possible ideas there. + */ + if (g_str_has_prefix (self->tls_client_key_path, "pkcs11:")) + { + curl_easy_setopt (req->easy, CURLOPT_SSLENGINE, "pkcs11"); + curl_easy_setopt (req->easy, CURLOPT_SSLENGINE_DEFAULT, 1L); + curl_easy_setopt (req->easy, CURLOPT_SSLKEYTYPE, "ENG"); + } + if (g_str_has_prefix (self->tls_client_cert_path, "pkcs11:")) + curl_easy_setopt (req->easy, CURLOPT_SSLCERTTYPE, "ENG"); + + curl_easy_setopt (req->easy, CURLOPT_SSLCERT, self->tls_client_cert_path); + curl_easy_setopt (req->easy, CURLOPT_SSLKEY, self->tls_client_key_path); + } + + if ((self->config_flags & OSTREE_FETCHER_FLAGS_TRANSFER_GZIP) > 0) + curl_easy_setopt (req->easy, CURLOPT_ACCEPT_ENCODING, ""); + + /* If we have e.g. basic auth in the URL string, let's honor that */ + const char *username = soup_uri_get_user (baseuri); + curl_easy_setopt (req->easy, CURLOPT_USERNAME, username); + const char *password = soup_uri_get_password (baseuri); + curl_easy_setopt (req->easy, CURLOPT_PASSWORD, password); + + /* We should only speak HTTP; TODO: only enable file if specified */ + curl_easy_setopt (req->easy, CURLOPT_PROTOCOLS, (long)(CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FILE)); + /* Picked the current version in F25 as of 20170127, since + * there are numerous HTTP/2 fixes since the original version in + * libcurl 7.43.0. + */ + if (!(self->config_flags & OSTREE_FETCHER_FLAGS_DISABLE_HTTP2)) + { +#if CURL_AT_LEAST_VERSION(7, 51, 0) + curl_easy_setopt (req->easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); +#endif + /* https://github.com/curl/curl/blob/curl-7_53_0/docs/examples/http2-download.c */ +#if (CURLPIPE_MULTIPLEX > 0) + /* wait for pipe connection to confirm */ + curl_easy_setopt (req->easy, CURLOPT_PIPEWAIT, 1L); +#endif + } + + curl_easy_setopt (req->easy, CURLOPT_WRITEFUNCTION, write_cb); + if (g_getenv ("OSTREE_DEBUG_HTTP")) + curl_easy_setopt (req->easy, CURLOPT_VERBOSE, 1L); + curl_easy_setopt (req->easy, CURLOPT_ERRORBUFFER, req->error); + /* Note that the "easy" object's privdata is the task */ + curl_easy_setopt (req->easy, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt (req->easy, CURLOPT_PROGRESSFUNCTION, prog_cb); + curl_easy_setopt (req->easy, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt (req->easy, CURLOPT_CONNECTTIMEOUT, 30L); + /* We used to set CURLOPT_LOW_SPEED_LIMIT and CURLOPT_LOW_SPEED_TIME + * here, but see https://github.com/ostreedev/ostree/issues/878#issuecomment-347228854 + * basically those options don't play well with HTTP2 at the moment + * where we can have lots of outstanding requests. Further, + * we could implement that functionality at a higher level + * more consistently too. + */ + + /* closure bindings -> task */ + curl_easy_setopt (req->easy, CURLOPT_PRIVATE, task); + curl_easy_setopt (req->easy, CURLOPT_WRITEDATA, task); + curl_easy_setopt (req->easy, CURLOPT_PROGRESSDATA, task); + + CURLMcode multi_rc = curl_multi_add_handle (self->multi, req->easy); + g_assert (multi_rc == CURLM_OK); +} + +static void +_ostree_fetcher_request_async (OstreeFetcher *self, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + gboolean is_membuf, + guint64 max_size, + int priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + FetcherRequest *req; + g_autoptr(GMainContext) mainctx = g_main_context_ref_thread_default (); + + /* We don't support multiple concurrent main contexts; take + * a ref to the first one, and require that later invocations + * share it. + */ + if (g_hash_table_size (self->outstanding_requests) == 0 + && mainctx != self->mainctx) + { + adopt_steal_mainctx (self, g_steal_pointer (&mainctx)); + } + else + { + g_assert (self->mainctx == mainctx); + } + + req = g_new0 (FetcherRequest, 1); + req->refcount = 1; + req->error[0]='\0'; + req->fetcher = self; + req->mirrorlist = g_ptr_array_ref (mirrorlist); + req->filename = g_strdup (filename); + req->max_size = max_size; + req->flags = flags; + req->is_membuf = is_membuf; + /* We'll allocate the tmpfile on demand, so we handle + * file I/O errors just in the write func. + */ + if (req->is_membuf) + req->output_buf = g_string_new (""); + + task = g_task_new (self, cancellable, callback, user_data); + /* We'll use the GTask priority for our own priority queue. */ + g_task_set_priority (task, priority); + g_task_set_source_tag (task, _ostree_fetcher_request_async); + g_task_set_task_data (task, req, (GDestroyNotify) request_unref); + + initiate_next_curl_request (req, task); + + g_hash_table_add (self->outstanding_requests, g_steal_pointer (&task)); +} + +void +_ostree_fetcher_request_to_tmpfile (OstreeFetcher *self, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + guint64 max_size, + int priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + _ostree_fetcher_request_async (self, mirrorlist, filename, flags, FALSE, + max_size, priority, cancellable, + callback, user_data); +} + +gboolean +_ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self, + GAsyncResult *result, + GLnxTmpfile *out_tmpf, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE); + + GTask *task = (GTask*)result; + FetcherRequest *req = g_task_get_task_data (task); + + if (!g_task_propagate_boolean (task, error)) + return FALSE; + + g_assert (!req->is_membuf); + *out_tmpf = req->tmpf; + req->tmpf.initialized = FALSE; /* Transfer ownership */ + + return TRUE; +} + +void +_ostree_fetcher_request_to_membuf (OstreeFetcher *self, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + guint64 max_size, + int priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + _ostree_fetcher_request_async (self, mirrorlist, filename, flags, TRUE, + max_size, priority, cancellable, + callback, user_data); +} + +gboolean +_ostree_fetcher_request_to_membuf_finish (OstreeFetcher *self, + GAsyncResult *result, + GBytes **out_buf, + GError **error) +{ + GTask *task; + FetcherRequest *req; + gpointer ret; + + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE); + + task = (GTask*)result; + req = g_task_get_task_data (task); + + ret = g_task_propagate_pointer (task, error); + if (!ret) + return FALSE; + + g_assert (req->is_membuf); + g_assert (out_buf); + *out_buf = ret; + + return TRUE; +} + +guint64 +_ostree_fetcher_bytes_transferred (OstreeFetcher *self) +{ + return self->bytes_transferred; +} diff --git a/src/libostree/ostree-fetcher-soup.c b/src/libostree/ostree-fetcher-soup.c new file mode 100644 index 0000000..970ac7a --- /dev/null +++ b/src/libostree/ostree-fetcher-soup.c @@ -0,0 +1,1306 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include +#include +#define LIBSOUP_USE_UNSTABLE_REQUEST_API +#include +#include +#include + +#include "libglnx.h" +#include "ostree-fetcher.h" +#include "ostree-fetcher-util.h" +#ifdef HAVE_LIBSOUP_CLIENT_CERTS +#include "ostree-tls-cert-interaction.h" +#endif +#include "ostree-enumtypes.h" +#include "ostree.h" +#include "ostree-repo-private.h" +#include "otutil.h" + +typedef enum { + OSTREE_FETCHER_STATE_PENDING, + OSTREE_FETCHER_STATE_DOWNLOADING, + OSTREE_FETCHER_STATE_COMPLETE +} OstreeFetcherState; + +typedef struct { + volatile int ref_count; + + SoupSession *session; /* not referenced */ + GMainContext *main_context; + volatile gint running; + GError *initialization_error; /* Any failure to load the db */ + + char *remote_name; + int base_tmpdir_dfd; + + GVariant *extra_headers; + gboolean transfer_gzip; + + /* Our active HTTP requests */ + GHashTable *outstanding; + + /* Shared across threads; be sure to lock. */ + GHashTable *output_stream_set; /* set */ + GMutex output_stream_set_lock; + + /* Also protected by output_stream_set_lock. */ + guint64 total_downloaded; + + GError *oob_error; + +} ThreadClosure; + +typedef struct { + volatile int ref_count; + + ThreadClosure *thread_closure; + GPtrArray *mirrorlist; /* list of base URIs */ + char *filename; /* relative name to fetch or NULL */ + guint mirrorlist_idx; + + OstreeFetcherState state; + + SoupRequest *request; + + gboolean is_membuf; + OstreeFetcherRequestFlags flags; + GInputStream *request_body; + GLnxTmpfile tmpf; + GOutputStream *out_stream; + + guint64 max_size; + guint64 current_size; + guint64 content_length; +} OstreeFetcherPendingURI; + +/* Used by session_thread_idle_add() */ +typedef void (*SessionThreadFunc) (ThreadClosure *thread_closure, + gpointer data); + +/* Used by session_thread_idle_add() */ +typedef struct { + ThreadClosure *thread_closure; + SessionThreadFunc function; + gpointer data; + GDestroyNotify notify; +} IdleClosure; + +struct OstreeFetcher +{ + GObject parent_instance; + + OstreeFetcherConfigFlags config_flags; + + GThread *session_thread; + ThreadClosure *thread_closure; +}; + +enum { + PROP_0, + PROP_CONFIG_FLAGS +}; + +G_DEFINE_TYPE (OstreeFetcher, _ostree_fetcher, G_TYPE_OBJECT) + +static ThreadClosure * +thread_closure_ref (ThreadClosure *thread_closure) +{ + int refcount; + g_return_val_if_fail (thread_closure != NULL, NULL); + refcount = g_atomic_int_add (&thread_closure->ref_count, 1); + g_assert (refcount > 0); + return thread_closure; +} + +static void +thread_closure_unref (ThreadClosure *thread_closure) +{ + g_return_if_fail (thread_closure != NULL); + + if (g_atomic_int_dec_and_test (&thread_closure->ref_count)) + { + /* The session thread should have cleared this by now. */ + g_assert (thread_closure->session == NULL); + + g_clear_pointer (&thread_closure->main_context, g_main_context_unref); + + g_clear_pointer (&thread_closure->extra_headers, (GDestroyNotify)g_variant_unref); + + g_clear_pointer (&thread_closure->output_stream_set, g_hash_table_unref); + g_mutex_clear (&thread_closure->output_stream_set_lock); + + g_clear_pointer (&thread_closure->oob_error, g_error_free); + + g_free (thread_closure->remote_name); + + g_slice_free (ThreadClosure, thread_closure); + } +} + +static void +idle_closure_free (IdleClosure *idle_closure) +{ + g_clear_pointer (&idle_closure->thread_closure, thread_closure_unref); + + if (idle_closure->notify != NULL) + idle_closure->notify (idle_closure->data); + + g_slice_free (IdleClosure, idle_closure); +} + +static OstreeFetcherPendingURI * +pending_uri_ref (OstreeFetcherPendingURI *pending) +{ + gint refcount; + g_return_val_if_fail (pending != NULL, NULL); + refcount = g_atomic_int_add (&pending->ref_count, 1); + g_assert (refcount > 0); + return pending; +} + +static void +pending_uri_unref (OstreeFetcherPendingURI *pending) +{ + if (!g_atomic_int_dec_and_test (&pending->ref_count)) + return; + + g_clear_pointer (&pending->thread_closure, thread_closure_unref); + + g_clear_pointer (&pending->mirrorlist, g_ptr_array_unref); + g_free (pending->filename); + g_clear_object (&pending->request); + g_clear_object (&pending->request_body); + glnx_tmpfile_clear (&pending->tmpf); + g_clear_object (&pending->out_stream); + g_free (pending); +} + +static gboolean +session_thread_idle_dispatch (gpointer data) +{ + IdleClosure *idle_closure = data; + + idle_closure->function (idle_closure->thread_closure, + idle_closure->data); + + return G_SOURCE_REMOVE; +} + +static void +session_thread_idle_add (ThreadClosure *thread_closure, + SessionThreadFunc function, + gpointer data, + GDestroyNotify notify) +{ + IdleClosure *idle_closure; + + g_return_if_fail (thread_closure != NULL); + g_return_if_fail (function != NULL); + + idle_closure = g_slice_new (IdleClosure); + idle_closure->thread_closure = thread_closure_ref (thread_closure); + idle_closure->function = function; + idle_closure->data = data; + idle_closure->notify = notify; + + g_main_context_invoke_full (thread_closure->main_context, + G_PRIORITY_DEFAULT, + session_thread_idle_dispatch, + idle_closure, /* takes ownership */ + (GDestroyNotify) idle_closure_free); +} + +static void +session_thread_add_logger (ThreadClosure *thread_closure, + gpointer data) +{ + glnx_unref_object SoupLogger *logger = NULL; + + logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, 500); + soup_session_add_feature (thread_closure->session, + SOUP_SESSION_FEATURE (logger)); +} + +static void +session_thread_config_flags (ThreadClosure *thread_closure, + gpointer data) +{ + OstreeFetcherConfigFlags config_flags; + + config_flags = GPOINTER_TO_UINT (data); + + if ((config_flags & OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE) > 0) + { + g_object_set (thread_closure->session, + SOUP_SESSION_SSL_STRICT, + FALSE, NULL); + } +} + +static void +on_authenticate (SoupSession *session, SoupMessage *msg, SoupAuth *auth, + gboolean retrying, gpointer user_data) +{ + ThreadClosure *thread_closure = user_data; + + if (msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED) + { + SoupURI *uri = NULL; + g_object_get (session, SOUP_SESSION_PROXY_URI, &uri, NULL); + if (retrying) + { + g_autofree char *s = soup_uri_to_string (uri, FALSE); + g_set_error (&thread_closure->oob_error, + G_IO_ERROR, G_IO_ERROR_PROXY_AUTH_FAILED, + "Invalid username or password for proxy '%s'", s); + } + else + soup_auth_authenticate (auth, soup_uri_get_user (uri), + soup_uri_get_password (uri)); + } +} + +static void +session_thread_set_proxy_cb (ThreadClosure *thread_closure, + gpointer data) +{ + SoupURI *proxy_uri = data; + + g_object_set (thread_closure->session, + SOUP_SESSION_PROXY_URI, + proxy_uri, NULL); + + /* libsoup won't necessarily pass any embedded username and password to proxy + * requests, so we have to be ready to handle 407 and handle them ourselves. + * See also: https://bugzilla.gnome.org/show_bug.cgi?id=772932 + * */ + if (soup_uri_get_user (proxy_uri) && + soup_uri_get_password (proxy_uri)) + { + g_signal_connect (thread_closure->session, "authenticate", + G_CALLBACK (on_authenticate), thread_closure); + } +} + +static void +session_thread_set_cookie_jar_cb (ThreadClosure *thread_closure, + gpointer data) +{ + SoupCookieJar *jar = data; + + soup_session_add_feature (thread_closure->session, + SOUP_SESSION_FEATURE (jar)); +} + +static void +session_thread_set_headers_cb (ThreadClosure *thread_closure, + gpointer data) +{ + GVariant *headers = data; + + g_clear_pointer (&thread_closure->extra_headers, (GDestroyNotify)g_variant_unref); + thread_closure->extra_headers = g_variant_ref (headers); +} + +#ifdef HAVE_LIBSOUP_CLIENT_CERTS +static void +session_thread_set_tls_interaction_cb (ThreadClosure *thread_closure, + gpointer data) +{ + const char *cert_and_key_path = data; /* str\0str\0 in one malloc buf */ + const char *cert_path = cert_and_key_path; + const char *key_path = cert_and_key_path + strlen (cert_and_key_path) + 1; + g_autoptr(OstreeTlsCertInteraction) interaction = NULL; + + /* The GTlsInteraction instance must be created in the + * session thread so it uses the correct GMainContext. */ + interaction = _ostree_tls_cert_interaction_new (cert_path, key_path); + + g_object_set (thread_closure->session, + SOUP_SESSION_TLS_INTERACTION, + interaction, NULL); +} +#endif + +static void +session_thread_set_tls_database_cb (ThreadClosure *thread_closure, + gpointer data) +{ + const char *db_path = data; + + if (db_path != NULL) + { + glnx_unref_object GTlsDatabase *tlsdb = NULL; + + g_clear_error (&thread_closure->initialization_error); + tlsdb = g_tls_file_database_new (db_path, &thread_closure->initialization_error); + + if (tlsdb) + g_object_set (thread_closure->session, + SOUP_SESSION_TLS_DATABASE, + tlsdb, NULL); + } + else + { + g_object_set (thread_closure->session, + SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, + TRUE, NULL); + } +} + +static void +session_thread_set_extra_user_agent_cb (ThreadClosure *thread_closure, + gpointer data) +{ + const char *extra_user_agent = data; + if (extra_user_agent != NULL) + { + g_autofree char *ua = + g_strdup_printf ("%s %s", OSTREE_FETCHER_USERAGENT_STRING, extra_user_agent); + g_object_set (thread_closure->session, SOUP_SESSION_USER_AGENT, ua, NULL); + } + else + { + g_object_set (thread_closure->session, SOUP_SESSION_USER_AGENT, + OSTREE_FETCHER_USERAGENT_STRING, NULL); + } +} + +static void +on_request_sent (GObject *object, GAsyncResult *result, gpointer user_data); + +static void +start_pending_request (ThreadClosure *thread_closure, + GTask *task) +{ + + OstreeFetcherPendingURI *pending; + GCancellable *cancellable; + + pending = g_task_get_task_data (task); + cancellable = g_task_get_cancellable (task); + + g_hash_table_add (thread_closure->outstanding, pending_uri_ref (pending)); + soup_request_send_async (pending->request, + cancellable, + on_request_sent, + g_object_ref (task)); +} + +static void +create_pending_soup_request (OstreeFetcherPendingURI *pending, + GError **error) +{ + OstreeFetcherURI *next_mirror = NULL; + g_autoptr(OstreeFetcherURI) uri = NULL; + + g_assert (pending->mirrorlist); + g_assert (pending->mirrorlist_idx < pending->mirrorlist->len); + + next_mirror = g_ptr_array_index (pending->mirrorlist, pending->mirrorlist_idx); + if (pending->filename) + uri = _ostree_fetcher_uri_new_subpath (next_mirror, pending->filename); + + g_clear_object (&pending->request); + + pending->request = soup_session_request_uri (pending->thread_closure->session, + (SoupURI*)(uri ? uri : next_mirror), error); +} + +static void +session_thread_request_uri (ThreadClosure *thread_closure, + gpointer data) +{ + GTask *task = G_TASK (data); + OstreeFetcherPendingURI *pending; + GCancellable *cancellable; + GError *local_error = NULL; + + pending = g_task_get_task_data (task); + cancellable = g_task_get_cancellable (task); + + /* If we caught an error in init, re-throw it for every request */ + if (thread_closure->initialization_error) + { + g_task_return_error (task, g_error_copy (thread_closure->initialization_error)); + return; + } + + create_pending_soup_request (pending, &local_error); + if (local_error != NULL) + { + g_task_return_error (task, local_error); + return; + } + + if (SOUP_IS_REQUEST_HTTP (pending->request) && thread_closure->extra_headers) + { + glnx_unref_object SoupMessage *msg = soup_request_http_get_message ((SoupRequestHTTP*) pending->request); + g_autoptr(GVariantIter) viter = g_variant_iter_new (thread_closure->extra_headers); + const char *key; + const char *value; + + while (g_variant_iter_next (viter, "(&s&s)", &key, &value)) + soup_message_headers_append (msg->request_headers, key, value); + } + + if (pending->is_membuf) + { + soup_request_send_async (pending->request, + cancellable, + on_request_sent, + g_object_ref (task)); + } + else + { + start_pending_request (thread_closure, task); + } +} + +static gpointer +ostree_fetcher_session_thread (gpointer data) +{ + ThreadClosure *closure = data; + g_autoptr(GMainContext) mainctx = g_main_context_ref (closure->main_context); + + /* This becomes the GMainContext that SoupSession schedules async + * callbacks and emits signals from. Make it the thread-default + * context for this thread before creating the session. */ + g_main_context_push_thread_default (mainctx); + + /* We retain ownership of the SoupSession reference. */ + closure->session = soup_session_async_new_with_options (SOUP_SESSION_USER_AGENT, OSTREE_FETCHER_USERAGENT_STRING, + SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE, + SOUP_SESSION_USE_THREAD_CONTEXT, TRUE, + SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_REQUESTER, + SOUP_SESSION_TIMEOUT, 60, + SOUP_SESSION_IDLE_TIMEOUT, 60, + NULL); + + if (closure->transfer_gzip) + soup_session_add_feature_by_type (closure->session, SOUP_TYPE_CONTENT_DECODER); + + /* XXX: Now that we have mirrorlist support, we could make this even smarter + * by spreading requests across mirrors. */ + gint max_conns; + g_object_get (closure->session, "max-conns-per-host", &max_conns, NULL); + if (max_conns < _OSTREE_MAX_OUTSTANDING_FETCHER_REQUESTS) + { + /* We download a lot of small objects in ostree, so this + * helps a lot. Also matches what most modern browsers do. + * + * Note since https://github.com/ostreedev/ostree/commit/f4d1334e19ce3ab2f8872b1e28da52044f559401 + * we don't do queuing in this libsoup backend, but we still + * want to override libsoup's currently conservative + * #define SOUP_SESSION_MAX_CONNS_PER_HOST_DEFAULT 2 (as of 2018-02-14). + */ + max_conns = _OSTREE_MAX_OUTSTANDING_FETCHER_REQUESTS; + g_object_set (closure->session, + "max-conns-per-host", + max_conns, NULL); + } + + /* This model ensures we don't hit a race using g_main_loop_quit(); + * see also what pull_termination_condition() in ostree-repo-pull.c + * is doing. + */ + while (g_atomic_int_get (&closure->running)) + g_main_context_iteration (closure->main_context, TRUE); + + /* Since the ThreadClosure may be finalized from any thread we + * unreference all data related to the SoupSession ourself to ensure + * it's freed in the same thread where it was created. */ + g_clear_pointer (&closure->outstanding, g_hash_table_unref); + g_clear_pointer (&closure->session, g_object_unref); + + thread_closure_unref (closure); + + /* Do this last, since libsoup uses g_main_current_source() which + * relies on it. + */ + g_main_context_pop_thread_default (mainctx); + + return NULL; +} + +static void +_ostree_fetcher_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeFetcher *self = OSTREE_FETCHER (object); + + switch (prop_id) + { + case PROP_CONFIG_FLAGS: + self->config_flags = g_value_get_flags (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +_ostree_fetcher_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeFetcher *self = OSTREE_FETCHER (object); + + switch (prop_id) + { + case PROP_CONFIG_FLAGS: + g_value_set_flags (value, self->config_flags); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +_ostree_fetcher_finalize (GObject *object) +{ + OstreeFetcher *self = OSTREE_FETCHER (object); + + /* Terminate the session thread. */ + g_atomic_int_set (&self->thread_closure->running, 0); + g_main_context_wakeup (self->thread_closure->main_context); + if (self->session_thread) + { + /* We need to explicitly synchronize to clean up TLS */ + if (self->session_thread != g_thread_self ()) + g_thread_join (self->session_thread); + else + g_clear_pointer (&self->session_thread, g_thread_unref); + } + g_clear_pointer (&self->thread_closure, thread_closure_unref); + + G_OBJECT_CLASS (_ostree_fetcher_parent_class)->finalize (object); +} + +static void +_ostree_fetcher_constructed (GObject *object) +{ + OstreeFetcher *self = OSTREE_FETCHER (object); + g_autoptr(GMainContext) main_context = NULL; + const char *http_proxy; + + main_context = g_main_context_new (); + + self->thread_closure = g_slice_new0 (ThreadClosure); + self->thread_closure->ref_count = 1; + self->thread_closure->main_context = g_main_context_ref (main_context); + self->thread_closure->running = 1; + self->thread_closure->transfer_gzip = (self->config_flags & OSTREE_FETCHER_FLAGS_TRANSFER_GZIP) != 0; + + self->thread_closure->outstanding = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)pending_uri_unref); + self->thread_closure->output_stream_set = g_hash_table_new_full (NULL, NULL, + (GDestroyNotify) NULL, + (GDestroyNotify) g_object_unref); + g_mutex_init (&self->thread_closure->output_stream_set_lock); + + if (g_getenv ("OSTREE_DEBUG_HTTP")) + { + session_thread_idle_add (self->thread_closure, + session_thread_add_logger, + NULL, (GDestroyNotify) NULL); + } + + if (self->config_flags != 0) + { + session_thread_idle_add (self->thread_closure, + session_thread_config_flags, + GUINT_TO_POINTER (self->config_flags), + (GDestroyNotify) NULL); + } + + http_proxy = g_getenv ("http_proxy"); + if (http_proxy != NULL && http_proxy[0] != '\0') + _ostree_fetcher_set_proxy (self, http_proxy); + + /* FIXME Maybe implement GInitableIface and use g_thread_try_new() + * so we can try to handle thread creation errors gracefully? */ + self->session_thread = g_thread_new ("fetcher-session-thread", + ostree_fetcher_session_thread, + thread_closure_ref (self->thread_closure)); + + G_OBJECT_CLASS (_ostree_fetcher_parent_class)->constructed (object); +} + +static void +_ostree_fetcher_class_init (OstreeFetcherClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = _ostree_fetcher_set_property; + gobject_class->get_property = _ostree_fetcher_get_property; + gobject_class->finalize = _ostree_fetcher_finalize; + gobject_class->constructed = _ostree_fetcher_constructed; + + g_object_class_install_property (gobject_class, + PROP_CONFIG_FLAGS, + g_param_spec_flags ("config-flags", + "", + "", + OSTREE_TYPE_FETCHER_CONFIG_FLAGS, + OSTREE_FETCHER_FLAGS_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static void +_ostree_fetcher_init (OstreeFetcher *self) +{ +} + +OstreeFetcher * +_ostree_fetcher_new (int tmpdir_dfd, + const char *remote_name, + OstreeFetcherConfigFlags flags) +{ + OstreeFetcher *self; + + self = g_object_new (OSTREE_TYPE_FETCHER, "config-flags", flags, NULL); + self->thread_closure->remote_name = g_strdup (remote_name); + self->thread_closure->base_tmpdir_dfd = tmpdir_dfd; + + return self; +} + +int +_ostree_fetcher_get_dfd (OstreeFetcher *fetcher) +{ + return fetcher->thread_closure->base_tmpdir_dfd; +} + +void +_ostree_fetcher_set_proxy (OstreeFetcher *self, + const char *http_proxy) +{ + SoupURI *proxy_uri; + + g_return_if_fail (OSTREE_IS_FETCHER (self)); + g_return_if_fail (http_proxy != NULL && http_proxy[0] != '\0'); + + proxy_uri = soup_uri_new (http_proxy); + + if (!proxy_uri) + { + g_warning ("Invalid proxy URI '%s'", http_proxy); + } + else + { + session_thread_idle_add (self->thread_closure, + session_thread_set_proxy_cb, + proxy_uri, /* takes ownership */ + (GDestroyNotify) soup_uri_free); + } +} + +void +_ostree_fetcher_set_cookie_jar (OstreeFetcher *self, + const char *jar_path) +{ + SoupCookieJar *jar; + + g_return_if_fail (OSTREE_IS_FETCHER (self)); + g_return_if_fail (jar_path != NULL); + + jar = soup_cookie_jar_text_new (jar_path, TRUE); + + session_thread_idle_add (self->thread_closure, + session_thread_set_cookie_jar_cb, + jar, /* takes ownership */ + (GDestroyNotify) g_object_unref); +} + +void +_ostree_fetcher_set_client_cert (OstreeFetcher *self, + const char *cert_path, + const char *key_path) +{ + g_autoptr(GString) buf = NULL; + g_return_if_fail (OSTREE_IS_FETCHER (self)); + + if (cert_path) + { + buf = g_string_new (cert_path); + g_string_append_c (buf, '\0'); + g_string_append (buf, key_path); + } + +#ifdef HAVE_LIBSOUP_CLIENT_CERTS + session_thread_idle_add (self->thread_closure, + session_thread_set_tls_interaction_cb, + g_string_free (g_steal_pointer (&buf), FALSE), + (GDestroyNotify) g_free); +#else + g_warning ("This version of OSTree is compiled without client side certificate support"); +#endif +} + +void +_ostree_fetcher_set_tls_database (OstreeFetcher *self, + const char *tlsdb_path) +{ + g_return_if_fail (OSTREE_IS_FETCHER (self)); + + session_thread_idle_add (self->thread_closure, + session_thread_set_tls_database_cb, + g_strdup (tlsdb_path), + (GDestroyNotify) g_free); +} + +void +_ostree_fetcher_set_extra_headers (OstreeFetcher *self, + GVariant *extra_headers) +{ + session_thread_idle_add (self->thread_closure, + session_thread_set_headers_cb, + g_variant_ref (extra_headers), + (GDestroyNotify) g_variant_unref); +} + +void +_ostree_fetcher_set_extra_user_agent (OstreeFetcher *self, + const char *extra_user_agent) +{ + session_thread_idle_add (self->thread_closure, + session_thread_set_extra_user_agent_cb, + g_strdup (extra_user_agent), + (GDestroyNotify) g_free); +} + +static gboolean +finish_stream (OstreeFetcherPendingURI *pending, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + struct stat stbuf; + + /* Close it here since we do an async fstat(), where we don't want + * to hit a bad fd. + */ + if (pending->out_stream) + { + if ((pending->flags & OSTREE_FETCHER_REQUEST_NUL_TERMINATION) > 0) + { + const guint8 nulchar = 0; + gsize bytes_written; + + if (!g_output_stream_write_all (pending->out_stream, &nulchar, 1, &bytes_written, + cancellable, error)) + goto out; + } + + if (!g_output_stream_close (pending->out_stream, cancellable, error)) + goto out; + + g_mutex_lock (&pending->thread_closure->output_stream_set_lock); + g_hash_table_remove (pending->thread_closure->output_stream_set, + pending->out_stream); + g_mutex_unlock (&pending->thread_closure->output_stream_set_lock); + } + + if (!pending->is_membuf) + { + if (!glnx_fstat (pending->tmpf.fd, &stbuf, error)) + goto out; + } + + pending->state = OSTREE_FETCHER_STATE_COMPLETE; + + if (!pending->is_membuf) + { + if (stbuf.st_size < pending->content_length) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Download incomplete"); + goto out; + } + else + { + g_mutex_lock (&pending->thread_closure->output_stream_set_lock); + pending->thread_closure->total_downloaded += stbuf.st_size; + g_mutex_unlock (&pending->thread_closure->output_stream_set_lock); + } + } + + ret = TRUE; + out: + (void) g_input_stream_close (pending->request_body, NULL, NULL); + return ret; +} + +static void +on_stream_read (GObject *object, + GAsyncResult *result, + gpointer user_data); + +static void +remove_pending (OstreeFetcherPendingURI *pending) +{ + /* Hold a temporary ref to ensure the reference to + * pending->thread_closure is valid. + */ + pending_uri_ref (pending); + g_hash_table_remove (pending->thread_closure->outstanding, pending); + pending_uri_unref (pending); +} + +static void +on_out_splice_complete (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + OstreeFetcherPendingURI *pending; + GCancellable *cancellable; + gssize bytes_written; + GError *local_error = NULL; + + pending = g_task_get_task_data (task); + cancellable = g_task_get_cancellable (task); + + bytes_written = g_output_stream_splice_finish ((GOutputStream *)object, + result, + &local_error); + if (bytes_written < 0) + goto out; + + g_input_stream_read_bytes_async (pending->request_body, + 8192, G_PRIORITY_DEFAULT, + cancellable, + on_stream_read, + g_object_ref (task)); + + out: + if (local_error) + { + g_task_return_error (task, local_error); + remove_pending (pending); + } + + g_object_unref (task); +} + +static void +on_stream_read (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + OstreeFetcherPendingURI *pending; + GCancellable *cancellable; + g_autoptr(GBytes) bytes = NULL; + gsize bytes_read; + GError *local_error = NULL; + + pending = g_task_get_task_data (task); + cancellable = g_task_get_cancellable (task); + + /* Only open the output stream on demand to ensure we use as + * few file descriptors as possible. + */ + if (!pending->out_stream) + { + if (!pending->is_membuf) + { + if (!_ostree_fetcher_tmpf_from_flags (pending->flags, pending->thread_closure->base_tmpdir_dfd, + &pending->tmpf, &local_error)) + goto out; + pending->out_stream = g_unix_output_stream_new (pending->tmpf.fd, FALSE); + } + else + { + pending->out_stream = g_memory_output_stream_new_resizable (); + } + + g_mutex_lock (&pending->thread_closure->output_stream_set_lock); + g_hash_table_add (pending->thread_closure->output_stream_set, + g_object_ref (pending->out_stream)); + g_mutex_unlock (&pending->thread_closure->output_stream_set_lock); + } + + /* Get a GBytes buffer */ + bytes = g_input_stream_read_bytes_finish ((GInputStream*)object, result, &local_error); + if (!bytes) + goto out; + bytes_read = g_bytes_get_size (bytes); + + /* Was this the end of the stream? */ + if (bytes_read == 0) + { + if (!finish_stream (pending, cancellable, &local_error)) + goto out; + if (pending->is_membuf) + { + g_task_return_pointer (task, + g_memory_output_stream_steal_as_bytes ((GMemoryOutputStream*)pending->out_stream), + (GDestroyNotify) g_bytes_unref); + } + else + { + if (lseek (pending->tmpf.fd, 0, SEEK_SET) < 0) + { + glnx_set_error_from_errno (&local_error); + g_task_return_error (task, g_steal_pointer (&local_error)); + } + else + g_task_return_boolean (task, TRUE); + } + remove_pending (pending); + } + else + { + /* Verify max size */ + if (pending->max_size > 0) + { + if (bytes_read > pending->max_size || + (bytes_read + pending->current_size) > pending->max_size) + { + g_autofree char *uristr = + soup_uri_to_string (soup_request_get_uri (pending->request), FALSE); + local_error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, + "URI %s exceeded maximum size of %" G_GUINT64_FORMAT " bytes", + uristr, pending->max_size); + goto out; + } + } + + pending->current_size += bytes_read; + + /* We do this instead of _write_bytes_async() as that's not + * guaranteed to do a complete write. + */ + { + g_autoptr(GInputStream) membuf = + g_memory_input_stream_new_from_bytes (bytes); + g_output_stream_splice_async (pending->out_stream, membuf, + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE, + G_PRIORITY_DEFAULT, + cancellable, + on_out_splice_complete, + g_object_ref (task)); + } + } + + out: + if (local_error) + { + g_task_return_error (task, local_error); + remove_pending (pending); + } + + g_object_unref (task); +} + +static void +on_request_sent (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + /* Hold a ref to the pending across this function, since we remove + * it from the hash early in some cases, not in others. */ + OstreeFetcherPendingURI *pending = pending_uri_ref (g_task_get_task_data (task)); + GCancellable *cancellable = g_task_get_cancellable (task); + GError *local_error = NULL; + glnx_unref_object SoupMessage *msg = NULL; + + pending->state = OSTREE_FETCHER_STATE_COMPLETE; + pending->request_body = soup_request_send_finish ((SoupRequest*) object, + result, &local_error); + + if (!pending->request_body) + goto out; + g_assert_no_error (local_error); + + if (SOUP_IS_REQUEST_HTTP (object)) + { + msg = soup_request_http_get_message ((SoupRequestHTTP*) object); + if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) + { + /* is there another mirror we can try? */ + if (pending->mirrorlist_idx + 1 < pending->mirrorlist->len) + { + pending->mirrorlist_idx++; + create_pending_soup_request (pending, &local_error); + if (local_error != NULL) + goto out; + + (void) g_input_stream_close (pending->request_body, NULL, NULL); + + start_pending_request (pending->thread_closure, task); + } + else + { + g_autofree char *uristring = + soup_uri_to_string (soup_request_get_uri (pending->request), FALSE); + + GIOErrorEnum code; + + switch (msg->status_code) + { + /* These statuses are internal to libsoup, and not standard HTTP ones: */ + case SOUP_STATUS_CANCELLED: + code = G_IO_ERROR_CANCELLED; + break; + case SOUP_STATUS_CANT_RESOLVE: + case SOUP_STATUS_CANT_CONNECT: + code = G_IO_ERROR_HOST_NOT_FOUND; + break; + case SOUP_STATUS_IO_ERROR: +#if !GLIB_CHECK_VERSION(2, 44, 0) + code = G_IO_ERROR_BROKEN_PIPE; +#else + code = G_IO_ERROR_CONNECTION_CLOSED; +#endif + break; + default: + code = _ostree_fetcher_http_status_code_to_io_error (msg->status_code); + break; + } + + { + g_autofree char *errmsg = + g_strdup_printf ("Server returned status %u: %s", + msg->status_code, + soup_status_get_phrase (msg->status_code)); + + /* Let's make OOB errors be the final one since they're probably + * the cause for the error here. */ + if (pending->thread_closure->oob_error) + { + local_error = + g_error_copy (pending->thread_closure->oob_error); + g_prefix_error (&local_error, "%s: ", errmsg); + } + else + local_error = g_error_new_literal (G_IO_ERROR, code, errmsg); + } + + if (pending->mirrorlist->len > 1) + g_prefix_error (&local_error, + "All %u mirrors failed. Last error was: ", + pending->mirrorlist->len); + if (pending->thread_closure->remote_name && + !((pending->flags & OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT) > 0 && + code == G_IO_ERROR_NOT_FOUND)) + _ostree_fetcher_journal_failure (pending->thread_closure->remote_name, + uristring, local_error->message); + + } + goto out; + } + } + + pending->state = OSTREE_FETCHER_STATE_DOWNLOADING; + + pending->content_length = soup_request_get_content_length (pending->request); + + g_input_stream_read_bytes_async (pending->request_body, + 8192, G_PRIORITY_DEFAULT, + cancellable, + on_stream_read, + g_object_ref (task)); + + out: + if (local_error) + { + if (pending->request_body) + (void) g_input_stream_close (pending->request_body, NULL, NULL); + g_task_return_error (task, local_error); + remove_pending (pending); + } + + pending_uri_unref (pending); + g_object_unref (task); +} + +static void +_ostree_fetcher_request_async (OstreeFetcher *self, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + gboolean is_membuf, + guint64 max_size, + int priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + OstreeFetcherPendingURI *pending; + + g_return_if_fail (OSTREE_IS_FETCHER (self)); + g_return_if_fail (mirrorlist != NULL); + g_return_if_fail (mirrorlist->len > 0); + + /* SoupRequest is created in session thread. */ + pending = g_new0 (OstreeFetcherPendingURI, 1); + pending->ref_count = 1; + pending->thread_closure = thread_closure_ref (self->thread_closure); + pending->mirrorlist = g_ptr_array_ref (mirrorlist); + pending->filename = g_strdup (filename); + pending->flags = flags; + pending->max_size = max_size; + pending->is_membuf = is_membuf; + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, _ostree_fetcher_request_async); + g_task_set_task_data (task, pending, (GDestroyNotify) pending_uri_unref); + + /* We'll use the GTask priority for our own priority queue. */ + g_task_set_priority (task, priority); + + session_thread_idle_add (self->thread_closure, + session_thread_request_uri, + g_object_ref (task), + (GDestroyNotify) g_object_unref); +} + +void +_ostree_fetcher_request_to_tmpfile (OstreeFetcher *self, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + guint64 max_size, + int priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + _ostree_fetcher_request_async (self, mirrorlist, filename, flags, FALSE, + max_size, priority, cancellable, + callback, user_data); +} + +gboolean +_ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self, + GAsyncResult *result, + GLnxTmpfile *out_tmpf, + GError **error) +{ + GTask *task; + OstreeFetcherPendingURI *pending; + gpointer ret; + + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE); + + task = (GTask*)result; + pending = g_task_get_task_data (task); + + ret = g_task_propagate_pointer (task, error); + if (!ret) + return FALSE; + + g_assert (!pending->is_membuf); + *out_tmpf = pending->tmpf; + pending->tmpf.initialized = FALSE; /* Transfer ownership */ + + return TRUE; +} + +void +_ostree_fetcher_request_to_membuf (OstreeFetcher *self, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + guint64 max_size, + int priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + _ostree_fetcher_request_async (self, mirrorlist, filename, flags, TRUE, + max_size, priority, cancellable, + callback, user_data); +} + +gboolean +_ostree_fetcher_request_to_membuf_finish (OstreeFetcher *self, + GAsyncResult *result, + GBytes **out_buf, + GError **error) +{ + GTask *task; + OstreeFetcherPendingURI *pending; + gpointer ret; + + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE); + + task = (GTask*)result; + pending = g_task_get_task_data (task); + + ret = g_task_propagate_pointer (task, error); + if (!ret) + return FALSE; + + g_assert (pending->is_membuf); + g_assert (out_buf); + *out_buf = ret; + + return TRUE; +} + + +guint64 +_ostree_fetcher_bytes_transferred (OstreeFetcher *self) +{ + g_return_val_if_fail (OSTREE_IS_FETCHER (self), 0); + + g_mutex_lock (&self->thread_closure->output_stream_set_lock); + + guint64 ret = self->thread_closure->total_downloaded; + + GLNX_HASH_TABLE_FOREACH (self->thread_closure->output_stream_set, + GFileOutputStream*, stream) + { + if (G_IS_FILE_DESCRIPTOR_BASED (stream)) + { + int fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)stream); + struct stat stbuf; + + if (glnx_fstat (fd, &stbuf, NULL)) + ret += stbuf.st_size; + } + } + + g_mutex_unlock (&self->thread_closure->output_stream_set_lock); + + return ret; +} diff --git a/src/libostree/ostree-fetcher-uri.c b/src/libostree/ostree-fetcher-uri.c new file mode 100644 index 0000000..485ed18 --- /dev/null +++ b/src/libostree/ostree-fetcher-uri.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2011,2017 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + + +#ifdef HAVE_LIBCURL +#include "ostree-soup-uri.h" +#else +#define LIBSOUP_USE_UNSTABLE_REQUEST_API +#include +#include +#include +#endif + +#include "ostree-fetcher.h" + +#include "libglnx.h" + +void +_ostree_fetcher_uri_free (OstreeFetcherURI *uri) +{ + if (uri) + soup_uri_free ((SoupURI*)uri); +} + +OstreeFetcherURI * +_ostree_fetcher_uri_parse (const char *str, + GError **error) +{ + SoupURI *soupuri = soup_uri_new (str); + if (soupuri == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to parse uri: %s", str); + return NULL; + } + return (OstreeFetcherURI*)soupuri; +} + +static OstreeFetcherURI * +_ostree_fetcher_uri_new_path_internal (OstreeFetcherURI *uri, + gboolean extend, + const char *path) +{ + SoupURI *newuri = soup_uri_copy ((SoupURI*)uri); + if (path) + { + if (extend) + { + const char *origpath = soup_uri_get_path ((SoupURI*)uri); + g_autofree char *newpath = g_build_filename (origpath, path, NULL); + soup_uri_set_path (newuri, newpath); + } + else + { + soup_uri_set_path (newuri, path); + } + } + return (OstreeFetcherURI*)newuri; +} + +OstreeFetcherURI * +_ostree_fetcher_uri_new_path (OstreeFetcherURI *uri, + const char *path) +{ + return _ostree_fetcher_uri_new_path_internal (uri, FALSE, path); +} + +OstreeFetcherURI * +_ostree_fetcher_uri_new_subpath (OstreeFetcherURI *uri, + const char *subpath) +{ + return _ostree_fetcher_uri_new_path_internal (uri, TRUE, subpath); +} + +OstreeFetcherURI * +_ostree_fetcher_uri_clone (OstreeFetcherURI *uri) +{ + return _ostree_fetcher_uri_new_subpath (uri, NULL); +} + +char * +_ostree_fetcher_uri_get_scheme (OstreeFetcherURI *uri) +{ + return g_strdup (soup_uri_get_scheme ((SoupURI*)uri)); +} + +char * +_ostree_fetcher_uri_get_path (OstreeFetcherURI *uri) +{ + return g_strdup (soup_uri_get_path ((SoupURI*)uri)); +} + +char * +_ostree_fetcher_uri_to_string (OstreeFetcherURI *uri) +{ + return soup_uri_to_string ((SoupURI*)uri, FALSE); +} diff --git a/src/libostree/ostree-fetcher-util.c b/src/libostree/ostree-fetcher-util.c new file mode 100644 index 0000000..1c3f810 --- /dev/null +++ b/src/libostree/ostree-fetcher-util.c @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2017 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_LIBSYSTEMD +#include +#endif + +#include "ostree-fetcher-util.h" +#include "otutil.h" + +typedef struct +{ + GBytes *result_buf; + gboolean done; + GError **error; +} + FetchUriSyncData; + +static void +fetch_uri_sync_on_complete (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + FetchUriSyncData *data = user_data; + + (void)_ostree_fetcher_request_to_membuf_finish ((OstreeFetcher*)object, + result, &data->result_buf, + data->error); + data->done = TRUE; +} + +static gboolean +_ostree_fetcher_mirrored_request_to_membuf_once (OstreeFetcher *fetcher, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + GBytes **out_contents, + guint64 max_size, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GMainContext) mainctx = NULL; + FetchUriSyncData data; + g_assert (error != NULL); + + memset (&data, 0, sizeof (data)); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + mainctx = g_main_context_new (); + g_main_context_push_thread_default (mainctx); + + data.done = FALSE; + data.error = error; + + _ostree_fetcher_request_to_membuf (fetcher, mirrorlist, filename, + flags, + max_size, OSTREE_FETCHER_DEFAULT_PRIORITY, + cancellable, fetch_uri_sync_on_complete, &data); + while (!data.done) + g_main_context_iteration (mainctx, TRUE); + + if (!data.result_buf) + { + if (flags & OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT) + { + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (error); + ret = TRUE; + *out_contents = NULL; + } + } + goto out; + } + + ret = TRUE; + *out_contents = g_steal_pointer (&data.result_buf); + out: + if (mainctx) + g_main_context_pop_thread_default (mainctx); + g_clear_pointer (&data.result_buf, (GDestroyNotify)g_bytes_unref); + return ret; +} + +gboolean +_ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + guint n_network_retries, + GBytes **out_contents, + guint64 max_size, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GError) local_error = NULL; + guint n_retries_remaining = n_network_retries; + + do + { + g_clear_error (&local_error); + if (_ostree_fetcher_mirrored_request_to_membuf_once (fetcher, mirrorlist, + filename, flags, + out_contents, max_size, + cancellable, &local_error)) + return TRUE; + } + while (_ostree_fetcher_should_retry_request (local_error, n_retries_remaining--)); + + g_assert (local_error != NULL); + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; +} + +/* Helper for callers who just want to fetch single one-off URIs */ +gboolean +_ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher, + OstreeFetcherURI *uri, + OstreeFetcherRequestFlags flags, + guint n_network_retries, + GBytes **out_contents, + guint64 max_size, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GPtrArray) mirrorlist = g_ptr_array_new (); + g_ptr_array_add (mirrorlist, uri); /* no transfer */ + return _ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist, NULL, flags, + n_network_retries, out_contents, max_size, + cancellable, error); +} + +#define OSTREE_HTTP_FAILURE_ID SD_ID128_MAKE(f0,2b,ce,89,a5,4e,4e,fa,b3,a9,4a,79,7d,26,20,4a) + +void +_ostree_fetcher_journal_failure (const char *remote_name, + const char *url, + const char *msg) +{ + /* Sanity - we don't want to log this when doing local/file pulls */ + if (!remote_name) + return; + ot_journal_send ("MESSAGE=libostree HTTP error from remote %s for <%s>: %s", + remote_name, url, msg, + "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_HTTP_FAILURE_ID), + "OSTREE_REMOTE=%s", remote_name, + "OSTREE_URL=%s", url, + "PRIORITY=%i", LOG_ERR, + NULL); +} + +/* Check whether a particular operation should be retried. This is entirely + * based on how it failed (if at all) last time, and whether the operation has + * some retries left. The retry count is set when the operation is first + * created, and must be decremented by the caller. (@n_retries_remaining == 0) + * will always return %FALSE from this function. + * + * FIXME: In future, we may decide to use transient failures like this as a hint + * to prioritise other mirrors for a particular pull operation (for example). */ +gboolean +_ostree_fetcher_should_retry_request (const GError *error, + guint n_retries_remaining) +{ + if (error == NULL) + g_debug ("%s: error: unset, n_retries_remaining: %u", + G_STRFUNC, n_retries_remaining); + else + g_debug ("%s: error: %u:%u %s, n_retries_remaining: %u", + G_STRFUNC, error->domain, error->code, error->message, + n_retries_remaining); + + if (error == NULL || n_retries_remaining == 0) + return FALSE; + + /* Return TRUE for transient errors. */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT) || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_HOST_NOT_FOUND) || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE) || + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT) || +#if !GLIB_CHECK_VERSION(2, 44, 0) + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE) || +#else + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED) || +#endif + g_error_matches (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND) || + g_error_matches (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_TEMPORARY_FAILURE)) + { + g_debug ("Should retry request (remaining: %u retries), due to transient error: %s", + n_retries_remaining, error->message); + return TRUE; + } + + return FALSE; +} + +/* Convert a HTTP status code representing an error from libsoup or libcurl to + * a #GIOErrorEnum. This will return %G_IO_ERROR_FAILED if the status code is + * unknown or otherwise unhandled. */ +GIOErrorEnum +_ostree_fetcher_http_status_code_to_io_error (guint status_code) +{ + switch (status_code) + { + case 403: /* SOUP_STATUS_FORBIDDEN */ + case 404: /* SOUP_STATUS_NOT_FOUND */ + case 410: /* SOUP_STATUS_GONE */ + return G_IO_ERROR_NOT_FOUND; + case 408: /* SOUP_STATUS_REQUEST_TIMEOUT */ + return G_IO_ERROR_TIMED_OUT; + default: + return G_IO_ERROR_FAILED; + } +} diff --git a/src/libostree/ostree-fetcher-util.h b/src/libostree/ostree-fetcher-util.h new file mode 100644 index 0000000..4693540 --- /dev/null +++ b/src/libostree/ostree-fetcher-util.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#ifndef __GI_SCANNER__ + +#include "ostree-fetcher.h" + +G_BEGIN_DECLS + +/* We used to only send "ostree/" but now include the version + * https://github.com/ostreedev/ostree/issues/1405 + * This came up in allowing Fedora infrastructure to work around a libcurl bug with HTTP2. + */ +#define OSTREE_FETCHER_USERAGENT_STRING (PACKAGE_NAME "/" PACKAGE_VERSION) + +static inline gboolean +_ostree_fetcher_tmpf_from_flags (OstreeFetcherRequestFlags flags, + int dfd, + GLnxTmpfile *tmpf, + GError **error) +{ + if ((flags & OSTREE_FETCHER_REQUEST_LINKABLE) > 0) + { + if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_RDWR | O_CLOEXEC, tmpf, error)) + return FALSE; + } + else if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, tmpf, error)) + return FALSE; + + if (!glnx_fchmod (tmpf->fd, 0644, error)) + return FALSE; + return TRUE; +} + +gboolean _ostree_fetcher_mirrored_request_to_membuf (OstreeFetcher *fetcher, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + guint n_network_retries, + GBytes **out_contents, + guint64 max_size, + GCancellable *cancellable, + GError **error); + +gboolean _ostree_fetcher_request_uri_to_membuf (OstreeFetcher *fetcher, + OstreeFetcherURI *uri, + OstreeFetcherRequestFlags flags, + guint n_network_retries, + GBytes **out_contents, + guint64 max_size, + GCancellable *cancellable, + GError **error); + +void _ostree_fetcher_journal_failure (const char *remote_name, + const char *url, + const char *msg); + +gboolean _ostree_fetcher_should_retry_request (const GError *error, + guint n_retries_remaining); + +GIOErrorEnum _ostree_fetcher_http_status_code_to_io_error (guint status_code); + +G_END_DECLS + +#endif diff --git a/src/libostree/ostree-fetcher.h b/src/libostree/ostree-fetcher.h new file mode 100644 index 0000000..32f3ea1 --- /dev/null +++ b/src/libostree/ostree-fetcher.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2012 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#ifndef __GI_SCANNER__ + +#include "libglnx.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_FETCHER (_ostree_fetcher_get_type ()) +#define OSTREE_FETCHER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_FETCHER, OstreeFetcher)) +#define OSTREE_FETCHER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_FETCHER, OstreeFetcherClass)) +#define OSTREE_IS_FETCHER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_FETCHER)) +#define OSTREE_IS_FETCHER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_FETCHER)) +#define OSTREE_FETCHER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_FETCHER, OstreeFetcherClass)) + +/* Lower values have higher priority */ +#define OSTREE_FETCHER_DEFAULT_PRIORITY 0 + +typedef struct OstreeFetcherURI OstreeFetcherURI; + +typedef struct OstreeFetcherClass OstreeFetcherClass; +typedef struct OstreeFetcher OstreeFetcher; + +struct OstreeFetcherClass +{ + GObjectClass parent_class; +}; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeFetcher, g_object_unref) + +typedef enum { + OSTREE_FETCHER_FLAGS_NONE = 0, + OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE = (1 << 0), + OSTREE_FETCHER_FLAGS_TRANSFER_GZIP = (1 << 1), + OSTREE_FETCHER_FLAGS_DISABLE_HTTP2 = (1 << 2), +} OstreeFetcherConfigFlags; + +typedef enum { + OSTREE_FETCHER_REQUEST_NUL_TERMINATION = (1 << 0), + OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT = (1 << 1), + OSTREE_FETCHER_REQUEST_LINKABLE = (1 << 2), +} OstreeFetcherRequestFlags; + +void +_ostree_fetcher_uri_free (OstreeFetcherURI *uri); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeFetcherURI, _ostree_fetcher_uri_free) + +OstreeFetcherURI * +_ostree_fetcher_uri_parse (const char *str, + GError **error); + +OstreeFetcherURI * +_ostree_fetcher_uri_clone (OstreeFetcherURI *uri); + +OstreeFetcherURI * +_ostree_fetcher_uri_new_path (OstreeFetcherURI *uri, + const char *subpath); + +OstreeFetcherURI * +_ostree_fetcher_uri_new_subpath (OstreeFetcherURI *uri, + const char *subpath); + +char * +_ostree_fetcher_uri_get_scheme (OstreeFetcherURI *uri); + +char * +_ostree_fetcher_uri_get_path (OstreeFetcherURI *uri); + +char * +_ostree_fetcher_uri_to_string (OstreeFetcherURI *uri); + +GType _ostree_fetcher_get_type (void) G_GNUC_CONST; + +OstreeFetcher *_ostree_fetcher_new (int tmpdir_dfd, + const char *remote_name, + OstreeFetcherConfigFlags flags); + +int _ostree_fetcher_get_dfd (OstreeFetcher *fetcher); + +void _ostree_fetcher_set_cookie_jar (OstreeFetcher *self, + const char *jar_path); + +void _ostree_fetcher_set_proxy (OstreeFetcher *fetcher, + const char *proxy); + +void _ostree_fetcher_set_client_cert (OstreeFetcher *fetcher, + const char *cert_path, + const char *key_path); + +void _ostree_fetcher_set_tls_database (OstreeFetcher *self, + const char *tlsdb_path); + +void _ostree_fetcher_set_extra_headers (OstreeFetcher *self, + GVariant *extra_headers); + +void _ostree_fetcher_set_extra_user_agent (OstreeFetcher *self, + const char *extra_user_agent); + +guint64 _ostree_fetcher_bytes_transferred (OstreeFetcher *self); + +void _ostree_fetcher_request_to_tmpfile (OstreeFetcher *self, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + guint64 max_size, + int priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean _ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self, + GAsyncResult *result, + GLnxTmpfile *out_tmpf, + GError **error); + +void _ostree_fetcher_request_to_membuf (OstreeFetcher *self, + GPtrArray *mirrorlist, + const char *filename, + OstreeFetcherRequestFlags flags, + guint64 max_size, + int priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean _ostree_fetcher_request_to_membuf_finish (OstreeFetcher *self, + GAsyncResult *result, + GBytes **out_buf, + GError **error); + + +G_END_DECLS + +#endif diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c new file mode 100644 index 0000000..95ed36e --- /dev/null +++ b/src/libostree/ostree-gpg-verifier.c @@ -0,0 +1,471 @@ +/* + * Copyright (C) 2011 Colin Walters + * Copyright (C) 2013 Sjoerd Simons + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Sjoerd Simons + */ + +#include "config.h" + +#include "libglnx.h" +#include "ostree-gpg-verifier.h" +#include "ot-gpg-utils.h" +#include "ostree-gpg-verify-result-private.h" +#include "otutil.h" + +#include +#include + +typedef struct { + GObjectClass parent_class; +} OstreeGpgVerifierClass; + +struct OstreeGpgVerifier { + GObject parent; + + GList *keyrings; + GPtrArray *keyring_data; + GPtrArray *key_ascii_files; +}; + +G_DEFINE_TYPE (OstreeGpgVerifier, _ostree_gpg_verifier, G_TYPE_OBJECT) + +static void +ostree_gpg_verifier_finalize (GObject *object) +{ + OstreeGpgVerifier *self = OSTREE_GPG_VERIFIER (object); + + g_list_free_full (self->keyrings, g_object_unref); + if (self->key_ascii_files) + g_ptr_array_unref (self->key_ascii_files); + g_clear_pointer (&self->keyring_data, (GDestroyNotify)g_ptr_array_unref); + + G_OBJECT_CLASS (_ostree_gpg_verifier_parent_class)->finalize (object); +} + +static void +_ostree_gpg_verifier_class_init (OstreeGpgVerifierClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = ostree_gpg_verifier_finalize; + + /* Initialize GPGME */ + gpgme_check_version (NULL); +} + +static void +_ostree_gpg_verifier_init (OstreeGpgVerifier *self) +{ + self->keyring_data = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref); +} + +static void +verify_result_finalized_cb (gpointer data, + GObject *finalized_verify_result) +{ + g_autofree gchar *tmp_dir = data; /* assume ownership */ + + /* XXX OstreeGpgVerifyResult could do this cleanup in its own + * finalize() method, but I didn't want this keyring hack + * bleeding into multiple classes. */ + + ot_gpgme_kill_agent (tmp_dir); + (void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_dir, NULL, NULL); +} + +OstreeGpgVerifyResult * +_ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, + GBytes *signed_data, + GBytes *signatures, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("GPG", error); + gpgme_error_t gpg_error = 0; + g_auto(gpgme_data_t) data_buffer = NULL; + g_auto(gpgme_data_t) signature_buffer = NULL; + g_autofree char *tmp_dir = NULL; + g_autoptr(GOutputStream) target_stream = NULL; + OstreeGpgVerifyResult *result = NULL; + gboolean success = FALSE; + GList *link; + int armor; + + /* GPGME has no API for using multiple keyrings (aka, gpg --keyring), + * so we concatenate all the keyring files into one pubring.gpg in a + * temporary directory, then tell GPGME to use that directory as the + * home directory. */ + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + goto out; + + result = g_initable_new (OSTREE_TYPE_GPG_VERIFY_RESULT, + cancellable, error, NULL); + if (result == NULL) + goto out; + + if (!ot_gpgme_ctx_tmp_home_dir (result->context, + &tmp_dir, &target_stream, + cancellable, error)) + goto out; + + for (link = self->keyrings; link != NULL; link = link->next) + { + g_autoptr(GFileInputStream) source_stream = NULL; + GFile *keyring_file = link->data; + gssize bytes_written; + GError *local_error = NULL; + + source_stream = g_file_read (keyring_file, cancellable, &local_error); + + /* Disregard non-existent keyrings. */ + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&local_error); + continue; + } + else if (local_error != NULL) + { + g_propagate_error (error, local_error); + goto out; + } + + bytes_written = g_output_stream_splice (target_stream, + G_INPUT_STREAM (source_stream), + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE, + cancellable, error); + if (bytes_written < 0) + goto out; + } + + for (guint i = 0; i < self->keyring_data->len; i++) + { + GBytes *keyringd = self->keyring_data->pdata[i]; + gsize len; + gsize bytes_written; + const guint8 *buf = g_bytes_get_data (keyringd, &len); + if (!g_output_stream_write_all (target_stream, buf, len, &bytes_written, + cancellable, error)) + goto out; + } + + if (!g_output_stream_close (target_stream, cancellable, error)) + goto out; + + /* Save the previous armor value - we need it on for importing ASCII keys */ + armor = gpgme_get_armor (result->context); + gpgme_set_armor (result->context, 1); + + /* Now, use the API to import ASCII-armored keys */ + if (self->key_ascii_files) + { + for (guint i = 0; i < self->key_ascii_files->len; i++) + { + const char *path = self->key_ascii_files->pdata[i]; + glnx_autofd int fd = -1; + g_auto(gpgme_data_t) kdata = NULL; + + if (!glnx_openat_rdonly (AT_FDCWD, path, TRUE, &fd, error)) + goto out; + + gpg_error = gpgme_data_new_from_fd (&kdata, fd); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Loading data from fd %i", fd); + goto out; + } + + gpg_error = gpgme_op_import (result->context, kdata); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Failed to import key"); + goto out; + } + } + } + + gpgme_set_armor (result->context, armor); + + /* Both the signed data and signature GBytes instances will outlive the + * gpgme_data_t structs, so we can safely reuse the GBytes memory buffer + * directly and avoid a copy. */ + + gpg_error = gpgme_data_new_from_mem (&data_buffer, + g_bytes_get_data (signed_data, NULL), + g_bytes_get_size (signed_data), + 0 /* do not copy */); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to read signed data"); + goto out; + } + + gpg_error = gpgme_data_new_from_mem (&signature_buffer, + g_bytes_get_data (signatures, NULL), + g_bytes_get_size (signatures), + 0 /* do not copy */); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to read signature"); + goto out; + } + + gpg_error = gpgme_op_verify (result->context, signature_buffer, data_buffer, NULL); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to complete signature verification"); + goto out; + } + + /* Result data is owned by the context. */ + result->details = gpgme_op_verify_result (result->context); + + gpgme_result_ref (result->details); + + success = TRUE; + +out: + if (success) + { + /* Keep the temporary directory around for the life of the result + * object so its GPGME context remains valid. It may yet have to + * extract user details from signing keys and will need to access + * the fabricated pubring.gpg keyring. */ + g_object_weak_ref (G_OBJECT (result), + verify_result_finalized_cb, + g_strdup (tmp_dir)); + } + else + { + /* Destroy the result object on error. */ + g_clear_object (&result); + + /* Try to clean up the temporary directory. */ + if (tmp_dir != NULL) + (void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_dir, NULL, NULL); + } + + return result; +} + +/* Given @path which should contain a GPG keyring file, add it + * to the list of trusted keys. + */ +void +_ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self, + GFile *path) +{ + g_return_if_fail (G_IS_FILE (path)); + + g_autofree gchar *path_str = g_file_get_path (path); + g_debug ("Adding GPG keyring file %s to verifier", path_str); + + self->keyrings = g_list_append (self->keyrings, g_object_ref (path)); +} + +/* Given @keyring which should be the contents of a GPG keyring file, add it to + * the list of trusted keys. + */ +void +_ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self, + GBytes *keyring, + const char *data_source) +{ + g_debug ("Adding GPG keyring data from %s to verifier", data_source); + + g_ptr_array_add (self->keyring_data, g_bytes_ref (keyring)); +} + +void +_ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self, + const char *path) +{ + g_debug ("Adding GPG key ASCII file %s to verifier", path); + + if (!self->key_ascii_files) + self->key_ascii_files = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (self->key_ascii_files, g_strdup (path)); +} + +gboolean +_ostree_gpg_verifier_add_keyfile_path (OstreeGpgVerifier *self, + const char *path, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GError) temp_error = NULL; + if (!_ostree_gpg_verifier_add_keyfile_dir_at (self, AT_FDCWD, path, + cancellable, &temp_error)) + { + g_assert (temp_error); + + /* If failed due to not being a directory, add the file as an ascii key. */ + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY)) + { + g_clear_error (&temp_error); + + _ostree_gpg_verifier_add_key_ascii_file (self, path); + } + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + + return FALSE; + } + } + return TRUE; +} + +/* Add files that exist one level below the directory at @path as ascii + * key files. If @path cannot be opened as a directory, + * an error is returned. + */ +gboolean +_ostree_gpg_verifier_add_keyfile_dir_at (OstreeGpgVerifier *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + + if (!glnx_dirfd_iterator_init_at (dfd, path, FALSE, + &dfd_iter, error)) + return FALSE; + + g_debug ("Adding GPG keyfile dir %s to verifier", path); + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, + cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (dent->d_type != DT_REG) + continue; + + /* TODO: Potentially open the files here and have the GPG verifier iterate + over the fds. See https://github.com/ostreedev/ostree/pull/1773#discussion_r235421900. */ + g_autofree char *iter_path = g_build_filename (path, dent->d_name, NULL); + + _ostree_gpg_verifier_add_key_ascii_file (self, iter_path); + } + + return TRUE; +} + +gboolean +_ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self, + GFile *path, + GCancellable *cancellable, + GError **error) +{ + return _ostree_gpg_verifier_add_keyring_dir_at (self, AT_FDCWD, + gs_file_get_path_cached (path), + cancellable, error); +} + +gboolean +_ostree_gpg_verifier_add_keyring_dir_at (OstreeGpgVerifier *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_at (dfd, path, FALSE, + &dfd_iter, error)) + return FALSE; + + g_debug ("Adding GPG keyring dir %s to verifier", path); + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (dent->d_type != DT_REG) + continue; + + const char *name = dent->d_name; + + /* Files with a .gpg suffix are typically keyrings except + * for trustdb.gpg, which is the GPG trust database. */ + + if (!g_str_has_suffix (name, ".gpg")) + continue; + + if (g_str_equal (name, "trustdb.gpg")) + continue; + + if (g_str_equal (name, "secring.gpg")) + continue; + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd_iter.fd, dent->d_name, TRUE, &fd, error)) + return FALSE; + + g_autoptr(GBytes) data = glnx_fd_readall_bytes (fd, cancellable, error); + if (!data) + return FALSE; + + g_ptr_array_add (self->keyring_data, g_steal_pointer (&data)); + } + + return TRUE; +} + +gboolean +_ostree_gpg_verifier_add_global_keyring_dir (OstreeGpgVerifier *self, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_GPG_VERIFIER (self), FALSE); + + const char *global_keyring_path = g_getenv ("OSTREE_GPG_HOME"); + if (global_keyring_path == NULL) + global_keyring_path = DATADIR "/ostree/trusted.gpg.d/"; + + if (g_file_test (global_keyring_path, G_FILE_TEST_IS_DIR)) + { + g_autoptr(GFile) global_keyring_dir = g_file_new_for_path (global_keyring_path); + if (!_ostree_gpg_verifier_add_keyring_dir (self, global_keyring_dir, + cancellable, error)) + return glnx_prefix_error (error, "Reading keyring directory '%s'", + gs_file_get_path_cached (global_keyring_dir)); + } + + return TRUE; +} + +OstreeGpgVerifier* +_ostree_gpg_verifier_new (void) +{ + return g_object_new (OSTREE_TYPE_GPG_VERIFIER, NULL); +} diff --git a/src/libostree/ostree-gpg-verifier.h b/src/libostree/ostree-gpg-verifier.h new file mode 100644 index 0000000..634d33b --- /dev/null +++ b/src/libostree/ostree-gpg-verifier.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2011 Colin Walters + * Copyright (C) 2013 Sjoerd Simons + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Sjoerd Simons + */ + +//#pragma once + +#include "ostree-gpg-verify-result.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_GPG_VERIFIER _ostree_gpg_verifier_get_type() +#define OSTREE_GPG_VERIFIER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_GPG_VERIFIER, OstreeGpgVerifier)) +#define OSTREE_IS_GPG_VERIFIER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_GPG_VERIFIER)) + +typedef struct OstreeGpgVerifier OstreeGpgVerifier; + +/* If this type becomes public in future, move this autoptr cleanup + * definition to the ostree-autocleanups.h header file. Right now it + * relies on glnx's fallback definition of the macro. */ +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeGpgVerifier, g_object_unref) + +GType _ostree_gpg_verifier_get_type (void); + +OstreeGpgVerifier *_ostree_gpg_verifier_new (void); + +OstreeGpgVerifyResult *_ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, + GBytes *signed_data, + GBytes *signatures, + GCancellable *cancellable, + GError **error); + +gboolean _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self, + GFile *path, + GCancellable *cancellable, + GError **error); + +gboolean _ostree_gpg_verifier_add_keyring_dir_at (OstreeGpgVerifier *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + +gboolean _ostree_gpg_verifier_add_global_keyring_dir (OstreeGpgVerifier *self, + GCancellable *cancellable, + GError **error); + +void _ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self, + GBytes *data, + const char *data_source); +void _ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self, + GFile *path); + +void _ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self, + const char *path); + +gboolean +_ostree_gpg_verifier_add_keyfile_path (OstreeGpgVerifier *self, + const char *path, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_gpg_verifier_add_keyfile_dir_at (OstreeGpgVerifier *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-gpg-verify-result-dummy.c b/src/libostree/ostree-gpg-verify-result-dummy.c new file mode 100644 index 0000000..a62ff91 --- /dev/null +++ b/src/libostree/ostree-gpg-verify-result-dummy.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * Copyright (C) 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libglnx.h" + +#include "ostree-gpg-verify-result.h" + +/** + * SECTION: ostree-gpg-verify-result + * @title: GPG signature verification results + * @short_description: Dummy functions for detached GPG signatures + * + * This file contain dummy functions for GPG signatures checks to + * provide API backward compatibility. + */ + +#ifndef OSTREE_DISABLE_GPGME +#error This file should not be compiled if GPG support is enabled +#endif + +/** + * OstreeGpgVerifyResult: + * + * Private instance structure. + */ +struct OstreeGpgVerifyResult { + GObject parent; +}; + + +typedef struct { + GObjectClass parent_class; +} OstreeGpgVerifyResultClass; + +static void ostree_gpg_verify_result_initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (OstreeGpgVerifyResult, + ostree_gpg_verify_result, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + ostree_gpg_verify_result_initable_iface_init)) + +static void +ostree_gpg_verify_result_class_init (OstreeGpgVerifyResultClass *class) +{ +} + +static void +ostree_gpg_verify_result_initable_iface_init (GInitableIface *iface) +{ +} + +static void +ostree_gpg_verify_result_init (OstreeGpgVerifyResult *result) +{ +} + +/** + * ostree_gpg_verify_result_count_all: + * @result: an #OstreeGpgVerifyResult + * + * Counts all the signatures in @result. + * + * Returns: signature count + */ +guint +ostree_gpg_verify_result_count_all (OstreeGpgVerifyResult *result) +{ + g_critical ("%s: GPG feature is disabled in a build time", __FUNCTION__); + return 0; +} + +/** + * ostree_gpg_verify_result_count_valid: + * @result: an #OstreeGpgVerifyResult + * + * Counts only the valid signatures in @result. + * + * Returns: valid signature count + */ +guint +ostree_gpg_verify_result_count_valid (OstreeGpgVerifyResult *result) +{ + g_critical ("%s: GPG feature is disabled in a build time", __FUNCTION__); + return 0; +} + +/** + * ostree_gpg_verify_result_lookup: + * @result: an #OstreeGpgVerifyResult + * @key_id: a GPG key ID or fingerprint + * @out_signature_index: (out): return location for the index of the signature + * signed by @key_id, or %NULL + * + * Searches @result for a signature signed by @key_id. If a match is found, + * the function returns %TRUE and sets @out_signature_index so that further + * signature details can be obtained through ostree_gpg_verify_result_get(). + * If no match is found, the function returns %FALSE and leaves + * @out_signature_index unchanged. + * + * Returns: %TRUE on success, %FALSE on failure + **/ +gboolean +ostree_gpg_verify_result_lookup (OstreeGpgVerifyResult *result, + const gchar *key_id, + guint *out_signature_index) +{ + g_critical ("%s: GPG feature is disabled in a build time", __FUNCTION__); + return FALSE; +} + +/** + * ostree_gpg_verify_result_get: + * @result: an #OstreeGpgVerifyResult + * @signature_index: which signature to get attributes from + * @attrs: (array length=n_attrs): Array of requested attributes + * @n_attrs: Length of the @attrs array + * + * Builds a #GVariant tuple of requested attributes for the GPG signature at + * @signature_index in @result. See the #OstreeGpgSignatureAttr description + * for the #GVariantType of each available attribute. + * + * It is a programmer error to request an invalid #OstreeGpgSignatureAttr or + * an invalid @signature_index. Use ostree_gpg_verify_result_count_all() to + * find the number of signatures in @result. + * + * Returns: a new, floating, #GVariant tuple + **/ +GVariant * +ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, + guint signature_index, + OstreeGpgSignatureAttr *attrs, + guint n_attrs) +{ + g_critical ("%s: GPG feature is disabled in a build time", __FUNCTION__); + return NULL; +} + +/** + * ostree_gpg_verify_result_get_all: + * @result: an #OstreeGpgVerifyResult + * @signature_index: which signature to get attributes from + * + * Builds a #GVariant tuple of all available attributes for the GPG signature + * at @signature_index in @result. + * + * The child values in the returned #GVariant tuple are ordered to match the + * #OstreeGpgSignatureAttr enumeration, which means the enum values can be + * used as index values in functions like g_variant_get_child(). See the + * #OstreeGpgSignatureAttr description for the #GVariantType of each + * available attribute. + * + * + * + * The #OstreeGpgSignatureAttr enumeration may be extended in the future + * with new attributes, which would affect the #GVariant tuple returned by + * this function. While the position and type of current child values in + * the #GVariant tuple will not change, to avoid backward-compatibility + * issues please do not depend on the tuple's overall size or + * type signature. + * + * + * + * It is a programmer error to request an invalid @signature_index. Use + * ostree_gpg_verify_result_count_all() to find the number of signatures in + * @result. + * + * Returns: a new, floating, #GVariant tuple + **/ +GVariant * +ostree_gpg_verify_result_get_all (OstreeGpgVerifyResult *result, + guint signature_index) +{ + g_return_val_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result), NULL); + + g_critical ("%s: GPG feature is disabled in a build time", __FUNCTION__); + return NULL; +} + +/** + * ostree_gpg_verify_result_describe: + * @result: an #OstreeGpgVerifyResult + * @signature_index: which signature to describe + * @output_buffer: a #GString to hold the description + * @line_prefix: (allow-none): optional line prefix string + * @flags: flags to adjust the description format + * + * Appends a brief, human-readable description of the GPG signature at + * @signature_index in @result to the @output_buffer. The description + * spans multiple lines. A @line_prefix string, if given, will precede + * each line of the description. + * + * The @flags argument is reserved for future variations to the description + * format. Currently must be 0. + * + * It is a programmer error to request an invalid @signature_index. Use + * ostree_gpg_verify_result_count_all() to find the number of signatures in + * @result. + */ +void +ostree_gpg_verify_result_describe (OstreeGpgVerifyResult *result, + guint signature_index, + GString *output_buffer, + const gchar *line_prefix, + OstreeGpgSignatureFormatFlags flags) +{ + g_autoptr(GVariant) variant = NULL; + + g_return_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result)); + + g_critical ("%s: GPG feature is disabled in a build time", __FUNCTION__); + + variant = ostree_gpg_verify_result_get_all (result, signature_index); + + ostree_gpg_verify_result_describe_variant (variant, output_buffer, line_prefix, flags); +} + +/** + * ostree_gpg_verify_result_describe_variant: + * @variant: a #GVariant from ostree_gpg_verify_result_get_all() + * @output_buffer: a #GString to hold the description + * @line_prefix: (allow-none): optional line prefix string + * @flags: flags to adjust the description format + * + * Similar to ostree_gpg_verify_result_describe() but takes a #GVariant of + * all attributes for a GPG signature instead of an #OstreeGpgVerifyResult + * and signature index. + * + * The @variant MUST have been created by + * ostree_gpg_verify_result_get_all(). + */ +void +ostree_gpg_verify_result_describe_variant (GVariant *variant, + GString *output_buffer, + const gchar *line_prefix, + OstreeGpgSignatureFormatFlags flags) +{ + const char *type_string; + + g_return_if_fail (variant != NULL); + g_return_if_fail (output_buffer != NULL); + + /* Verify the variant's type string. This code is + * not prepared to handle just any random GVariant. */ + type_string = g_variant_get_type_string (variant); + g_return_if_fail (strcmp (type_string, "(bbbbbsxxsssssxx)") == 0); + + g_string_append (output_buffer, + "GPG feature is disabled in a build time\n"); + + g_critical ("%s: GPG feature is disabled in a build time", __FUNCTION__); +} + +/** + * ostree_gpg_verify_result_require_valid_signature: + * @result: (nullable): an #OstreeGpgVerifyResult + * @error: A #GError + * + * Checks if the result contains at least one signature from the + * trusted keyring. You can call this function immediately after + * ostree_repo_verify_summary() or ostree_repo_verify_commit_ext() - + * it will handle the %NULL @result and filled @error too. + * + * Returns: %TRUE if @result was not %NULL and had at least one + * signature from trusted keyring, otherwise %FALSE + * + * Since: 2016.6 + */ +gboolean +ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result, + GError **error) +{ + if (result == NULL) + return FALSE; + + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "'%s': GPG feature is disabled in a build time", + __FUNCTION__); + return FALSE; +} + +G_DEFINE_QUARK (OstreeGpgError, ostree_gpg_error) diff --git a/src/libostree/ostree-gpg-verify-result-private.h b/src/libostree/ostree-gpg-verify-result-private.h new file mode 100644 index 0000000..66d7e56 --- /dev/null +++ b/src/libostree/ostree-gpg-verify-result-private.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-gpg-verify-result.h" + +#include "otutil.h" + +/** + * OstreeGpgVerifyResult: + * + * Private instance structure. + */ +struct OstreeGpgVerifyResult { + GObject parent; + + gpgme_ctx_t context; + gpgme_verify_result_t details; +}; diff --git a/src/libostree/ostree-gpg-verify-result.c b/src/libostree/ostree-gpg-verify-result.c new file mode 100644 index 0000000..67270c8 --- /dev/null +++ b/src/libostree/ostree-gpg-verify-result.c @@ -0,0 +1,830 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "libglnx.h" + +#include "ostree-gpg-verify-result-private.h" + +/** + * SECTION: ostree-gpg-verify-result + * @title: GPG signature verification results + * @short_description: Inspect detached GPG signatures + * + * #OstreeGpgVerifyResult contains verification details for GPG signatures + * read from a detached #OstreeRepo metadata object. + * + * Use ostree_gpg_verify_result_count_all() and + * ostree_gpg_verify_result_count_valid() to quickly check overall signature + * validity. + * + * Use ostree_gpg_verify_result_lookup() to find a signature by the key ID + * or fingerprint of the signing key. + * + * For more in-depth inspection, such as presenting signature details to the + * user, pass an array of attribute values to ostree_gpg_verify_result_get() + * or get all signature details with ostree_gpg_verify_result_get_all(). + */ + +typedef struct { + GObjectClass parent_class; +} OstreeGpgVerifyResultClass; + +/* This must stay synchronized with the enum declaration. */ +static OstreeGpgSignatureAttr all_signature_attrs[] = { + OSTREE_GPG_SIGNATURE_ATTR_VALID, + OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED, + OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED, + OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED, + OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING, + OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT, + OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP, + OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP, + OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, + OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME, + OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, + OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, + OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY, + OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP, + OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP_PRIMARY, +}; + +static void ostree_gpg_verify_result_initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (OstreeGpgVerifyResult, + ostree_gpg_verify_result, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + ostree_gpg_verify_result_initable_iface_init)) + +static gboolean +signature_is_valid (gpgme_signature_t signature) +{ + /* Mimic the way librepo tests for a valid signature, checking both + * summary and status fields. + * + * - VALID summary flag means the signature is fully valid. + * - GREEN summary flag means the signature is valid with caveats. + * - No summary but also no error means the signature is valid but + * the signing key is not certified with a trusted signature. + */ + return (signature->summary & GPGME_SIGSUM_VALID) || + (signature->summary & GPGME_SIGSUM_GREEN) || + (signature->summary == 0 && signature->status == GPG_ERR_NO_ERROR); +} + +static gboolean +signing_key_is_revoked (gpgme_signature_t signature) +{ + /* In my testing, GPGME does not set the GPGME_SIGSUM_KEY_REVOKED summary + * bit on a revoked signing key but rather GPGME_SIGSUM_SYS_ERROR and the + * status field shows GPG_ERR_CERT_REVOKED. Turns out GPGME is expecting + * GPG_ERR_CERT_REVOKED in the validity_reason field which would then set + * the summary bit. + * + * Reported to GPGME: https://bugs.g10code.com/gnupg/issue1929 + */ + + return (signature->summary & GPGME_SIGSUM_KEY_REVOKED) || + ((signature->summary & GPGME_SIGSUM_SYS_ERROR) && + gpgme_err_code (signature->status) == GPG_ERR_CERT_REVOKED); +} + +static void +ostree_gpg_verify_result_finalize (GObject *object) +{ + OstreeGpgVerifyResult *result = OSTREE_GPG_VERIFY_RESULT (object); + + if (result->context != NULL) + gpgme_release (result->context); + + if (result->details != NULL) + gpgme_result_unref (result->details); + + G_OBJECT_CLASS (ostree_gpg_verify_result_parent_class)->finalize (object); +} + +static gboolean +ostree_gpg_verify_result_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + OstreeGpgVerifyResult *result = OSTREE_GPG_VERIFY_RESULT (initable); + gpgme_error_t gpg_error; + gboolean ret = FALSE; + + gpg_error = gpgme_new (&result->context); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to create context"); + goto out; + } + + ret = TRUE; + +out: + return ret; +} + +static void +ostree_gpg_verify_result_class_init (OstreeGpgVerifyResultClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + object_class->finalize = ostree_gpg_verify_result_finalize; +} + +static void +ostree_gpg_verify_result_init (OstreeGpgVerifyResult *result) +{ +} + +static void +ostree_gpg_verify_result_initable_iface_init (GInitableIface *iface) +{ + iface->init = ostree_gpg_verify_result_initable_init; +} + +/** + * ostree_gpg_verify_result_count_all: + * @result: an #OstreeGpgVerifyResult + * + * Counts all the signatures in @result. + * + * Returns: signature count + */ +guint +ostree_gpg_verify_result_count_all (OstreeGpgVerifyResult *result) +{ + gpgme_signature_t signature; + guint count = 0; + + g_return_val_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result), 0); + + for (signature = result->details->signatures; + signature != NULL; + signature = signature->next) + { + count++; + } + + return count; +} + +/** + * ostree_gpg_verify_result_count_valid: + * @result: an #OstreeGpgVerifyResult + * + * Counts only the valid signatures in @result. + * + * Returns: valid signature count + */ +guint +ostree_gpg_verify_result_count_valid (OstreeGpgVerifyResult *result) +{ + gpgme_signature_t signature; + guint count = 0; + + g_return_val_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result), 0); + + for (signature = result->details->signatures; + signature != NULL; + signature = signature->next) + { + if (signature_is_valid (signature)) + count++; + } + + return count; +} + +/** + * ostree_gpg_verify_result_lookup: + * @result: an #OstreeGpgVerifyResult + * @key_id: a GPG key ID or fingerprint + * @out_signature_index: (out): return location for the index of the signature + * signed by @key_id, or %NULL + * + * Searches @result for a signature signed by @key_id. If a match is found, + * the function returns %TRUE and sets @out_signature_index so that further + * signature details can be obtained through ostree_gpg_verify_result_get(). + * If no match is found, the function returns %FALSE and leaves + * @out_signature_index unchanged. + * + * Returns: %TRUE on success, %FALSE on failure + **/ +gboolean +ostree_gpg_verify_result_lookup (OstreeGpgVerifyResult *result, + const gchar *key_id, + guint *out_signature_index) +{ + g_auto(gpgme_key_t) lookup_key = NULL; + gpgme_signature_t signature; + guint signature_index; + + g_return_val_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result), FALSE); + g_return_val_if_fail (key_id != NULL, FALSE); + + /* fetch requested key_id from keyring to canonicalise ID */ + (void) gpgme_get_key (result->context, key_id, &lookup_key, 0); + + if (lookup_key == NULL) + { + g_debug ("Could not find key ID %s to lookup signature.", key_id); + return FALSE; + } + + for (signature = result->details->signatures, signature_index = 0; + signature != NULL; + signature = signature->next, signature_index++) + { + g_auto(gpgme_key_t) signature_key = NULL; + + (void) gpgme_get_key (result->context, signature->fpr, &signature_key, 0); + + if (signature_key == NULL) + { + g_debug ("Could not find key when looking up signature from %s.", signature->fpr); + continue; + } + + /* the first subkey in the list is the primary key */ + if (!g_strcmp0 (lookup_key->subkeys->fpr, + signature_key->subkeys->fpr)) + { + if (out_signature_index != NULL) + *out_signature_index = signature_index; + /* Note early return */ + return TRUE; + } + + } + + return FALSE; +} + +/** + * ostree_gpg_verify_result_get: + * @result: an #OstreeGpgVerifyResult + * @signature_index: which signature to get attributes from + * @attrs: (array length=n_attrs): Array of requested attributes + * @n_attrs: Length of the @attrs array + * + * Builds a #GVariant tuple of requested attributes for the GPG signature at + * @signature_index in @result. See the #OstreeGpgSignatureAttr description + * for the #GVariantType of each available attribute. + * + * It is a programmer error to request an invalid #OstreeGpgSignatureAttr or + * an invalid @signature_index. Use ostree_gpg_verify_result_count_all() to + * find the number of signatures in @result. + * + * Returns: a new, floating, #GVariant tuple + **/ +GVariant * +ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, + guint signature_index, + OstreeGpgSignatureAttr *attrs, + guint n_attrs) +{ + GVariantBuilder builder; + g_auto(gpgme_key_t) key = NULL; + gpgme_signature_t signature; + guint ii; + + g_return_val_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result), NULL); + g_return_val_if_fail (attrs != NULL, NULL); + g_return_val_if_fail (n_attrs > 0, NULL); + + signature = result->details->signatures; + while (signature != NULL && signature_index > 0) + { + signature = signature->next; + signature_index--; + } + + g_return_val_if_fail (signature != NULL, NULL); + + /* Lookup the signing key if we need it. Note, failure to find + * the key is not a fatal error. There's an attribute for that + * (OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING). */ + for (ii = 0; ii < n_attrs; ii++) + { + if (attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_NAME || + attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL || + attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY || + attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP || + attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP_PRIMARY) + { + (void) gpgme_get_key (result->context, signature->fpr, &key, 0); + break; + } + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); + + for (ii = 0; ii < n_attrs; ii++) + { + GVariant *child; + gboolean v_boolean; + const char *v_string = NULL; + gint64 v_int64; + + switch (attrs[ii]) + { + case OSTREE_GPG_SIGNATURE_ATTR_VALID: + v_boolean = signature_is_valid (signature); + child = g_variant_new_boolean (v_boolean); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED: + v_boolean = ((signature->summary & GPGME_SIGSUM_SIG_EXPIRED) != 0); + child = g_variant_new_boolean (v_boolean); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED: + v_boolean = ((signature->summary & GPGME_SIGSUM_KEY_EXPIRED) != 0); + child = g_variant_new_boolean (v_boolean); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED: + v_boolean = signing_key_is_revoked (signature); + child = g_variant_new_boolean (v_boolean); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING: + v_boolean = ((signature->summary & GPGME_SIGSUM_KEY_MISSING) != 0); + child = g_variant_new_boolean (v_boolean); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT: + child = g_variant_new_string (signature->fpr); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP: + child = g_variant_new_int64 ((gint64) signature->timestamp); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP: + child = g_variant_new_int64 ((gint64) signature->exp_timestamp); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME: + v_string = gpgme_pubkey_algo_name (signature->pubkey_algo); + if (v_string == NULL) + v_string = "[unknown name]"; + child = g_variant_new_string (v_string); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME: + v_string = gpgme_hash_algo_name (signature->hash_algo); + if (v_string == NULL) + v_string = "[unknown name]"; + child = g_variant_new_string (v_string); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_USER_NAME: + if (key != NULL && key->uids != NULL) + v_string = key->uids->name; + if (v_string == NULL) + v_string = "[unknown name]"; + child = g_variant_new_string (v_string); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL: + if (key != NULL && key->uids != NULL) + v_string = key->uids->email; + if (v_string == NULL) + v_string = "[unknown email]"; + child = g_variant_new_string (v_string); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY: + if (key != NULL && key->subkeys != NULL) + v_string = key->subkeys->fpr; + if (v_string == NULL) + v_string = ""; + child = g_variant_new_string (v_string); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP: + v_int64 = 0; + if (key != NULL) + { + gpgme_subkey_t subkey = key->subkeys; + + while (subkey != NULL && (g_strcmp0 (subkey->fpr, signature->fpr) != 0)) + subkey = subkey->next; + + if (subkey != NULL) + v_int64 = subkey->expires; + } + child = g_variant_new_int64 (v_int64); + break; + + case OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP_PRIMARY: + if (key != NULL && key->subkeys != NULL) + v_int64 = key->subkeys->expires; + else + v_int64 = 0; + child = g_variant_new_int64 (v_int64); + break; + + default: + g_critical ("Invalid signature attribute (%d)", attrs[ii]); + g_variant_builder_clear (&builder); + return NULL; + } + + g_variant_builder_add_value (&builder, child); + } + + return g_variant_builder_end (&builder); +} + +/** + * ostree_gpg_verify_result_get_all: + * @result: an #OstreeGpgVerifyResult + * @signature_index: which signature to get attributes from + * + * Builds a #GVariant tuple of all available attributes for the GPG signature + * at @signature_index in @result. + * + * The child values in the returned #GVariant tuple are ordered to match the + * #OstreeGpgSignatureAttr enumeration, which means the enum values can be + * used as index values in functions like g_variant_get_child(). See the + * #OstreeGpgSignatureAttr description for the #GVariantType of each + * available attribute. + * + * + * + * The #OstreeGpgSignatureAttr enumeration may be extended in the future + * with new attributes, which would affect the #GVariant tuple returned by + * this function. While the position and type of current child values in + * the #GVariant tuple will not change, to avoid backward-compatibility + * issues please do not depend on the tuple's overall size or + * type signature. + * + * + * + * It is a programmer error to request an invalid @signature_index. Use + * ostree_gpg_verify_result_count_all() to find the number of signatures in + * @result. + * + * Returns: a new, floating, #GVariant tuple + **/ +GVariant * +ostree_gpg_verify_result_get_all (OstreeGpgVerifyResult *result, + guint signature_index) +{ + g_return_val_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result), NULL); + + return ostree_gpg_verify_result_get (result, signature_index, + all_signature_attrs, + G_N_ELEMENTS (all_signature_attrs)); +} + +/** + * ostree_gpg_verify_result_describe: + * @result: an #OstreeGpgVerifyResult + * @signature_index: which signature to describe + * @output_buffer: a #GString to hold the description + * @line_prefix: (allow-none): optional line prefix string + * @flags: flags to adjust the description format + * + * Appends a brief, human-readable description of the GPG signature at + * @signature_index in @result to the @output_buffer. The description + * spans multiple lines. A @line_prefix string, if given, will precede + * each line of the description. + * + * The @flags argument is reserved for future variations to the description + * format. Currently must be 0. + * + * It is a programmer error to request an invalid @signature_index. Use + * ostree_gpg_verify_result_count_all() to find the number of signatures in + * @result. + */ +void +ostree_gpg_verify_result_describe (OstreeGpgVerifyResult *result, + guint signature_index, + GString *output_buffer, + const gchar *line_prefix, + OstreeGpgSignatureFormatFlags flags) +{ + g_autoptr(GVariant) variant = NULL; + + g_return_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result)); + + variant = ostree_gpg_verify_result_get_all (result, signature_index); + + ostree_gpg_verify_result_describe_variant (variant, output_buffer, line_prefix, flags); +} + +static void +append_expire_info (GString *output_buffer, + const gchar *line_prefix, + const gchar *exp_type, + gint64 exp_timestamp, + gboolean expired) +{ + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + + g_autoptr(GDateTime) date_time_utc = g_date_time_new_from_unix_utc (exp_timestamp); + if (date_time_utc == NULL) + { + g_string_append_printf (output_buffer, + "%s expiry timestamp (%" G_GINT64_FORMAT ") is invalid\n", + exp_type, + exp_timestamp); + return; + } + + g_autoptr(GDateTime) date_time_local = g_date_time_to_local (date_time_utc); + g_autofree char *formatted_date_time = g_date_time_format (date_time_local, "%c"); + + if (expired) + { + g_string_append_printf (output_buffer, + "%s expired %s\n", + exp_type, + formatted_date_time); + } + else + { + g_string_append_printf (output_buffer, + "%s expires %s\n", + exp_type, + formatted_date_time); + } +} + +/** + * ostree_gpg_verify_result_describe_variant: + * @variant: a #GVariant from ostree_gpg_verify_result_get_all() + * @output_buffer: a #GString to hold the description + * @line_prefix: (allow-none): optional line prefix string + * @flags: flags to adjust the description format + * + * Similar to ostree_gpg_verify_result_describe() but takes a #GVariant of + * all attributes for a GPG signature instead of an #OstreeGpgVerifyResult + * and signature index. + * + * The @variant MUST have been created by + * ostree_gpg_verify_result_get_all(). + */ +void +ostree_gpg_verify_result_describe_variant (GVariant *variant, + GString *output_buffer, + const gchar *line_prefix, + OstreeGpgSignatureFormatFlags flags) +{ + g_autoptr(GDateTime) date_time_utc = NULL; + g_autoptr(GDateTime) date_time_local = NULL; + g_autofree char *formatted_date_time = NULL; + gint64 timestamp; + gint64 exp_timestamp; + gint64 key_exp_timestamp; + gint64 key_exp_timestamp_primary; + const char *type_string; + const char *fingerprint; + const char *fingerprint_primary; + const char *pubkey_algo; + const char *user_name; + const char *user_email; + const char *key_id; + gboolean valid; + gboolean sig_expired; + gboolean key_expired; + gboolean key_revoked; + gboolean key_missing; + gsize len; + + g_return_if_fail (variant != NULL); + g_return_if_fail (output_buffer != NULL); + + /* Verify the variant's type string. This code is + * not prepared to handle just any random GVariant. */ + type_string = g_variant_get_type_string (variant); + g_return_if_fail (strcmp (type_string, "(bbbbbsxxsssssxx)") == 0); + + /* The default format roughly mimics the verify output generated by + * check_sig_and_print() in gnupg/g10/mainproc.c, though obviously + * greatly simplified. */ + + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_VALID, + "b", &valid); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED, + "b", &sig_expired); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED, + "b", &key_expired); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED, + "b", &key_revoked); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING, + "b", &key_missing); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT, + "&s", &fingerprint); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY, + "&s", &fingerprint_primary); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP, + "x", ×tamp); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP, + "x", &exp_timestamp); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, + "&s", &pubkey_algo); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, + "&s", &user_name); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, + "&s", &user_email); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP, + "x", &key_exp_timestamp); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP_PRIMARY, + "x", &key_exp_timestamp_primary); + + len = strlen (fingerprint); + key_id = (len > 16) ? fingerprint + len - 16 : fingerprint; + + date_time_utc = g_date_time_new_from_unix_utc (timestamp); + if (date_time_utc == NULL) + { + g_string_append_printf (output_buffer, + "Can't check signature: timestamp %" G_GINT64_FORMAT " is invalid\n", + timestamp); + return; + } + + date_time_local = g_date_time_to_local (date_time_utc); + formatted_date_time = g_date_time_format (date_time_local, "%c"); + + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + + g_string_append_printf (output_buffer, + "Signature made %s using %s key ID %s\n", + formatted_date_time, pubkey_algo, key_id); + + g_clear_pointer (&date_time_utc, g_date_time_unref); + g_clear_pointer (&date_time_local, g_date_time_unref); + g_clear_pointer (&formatted_date_time, g_free); + + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + + if (key_missing) + { + g_string_append (output_buffer, + "Can't check signature: public key not found\n"); + } + else if (valid) + { + g_string_append_printf (output_buffer, + "Good signature from \"%s <%s>\"\n", + user_name, user_email); + } + else if (key_revoked) + { + g_string_append (output_buffer, "Key revoked\n"); + } + else if (sig_expired) + { + g_string_append_printf (output_buffer, + "Expired signature from \"%s <%s>\"\n", + user_name, user_email); + } + else + { + g_string_append_printf (output_buffer, + "BAD signature from \"%s <%s>\"\n", + user_name, user_email); + } + + if (!key_missing && (g_strcmp0 (fingerprint, fingerprint_primary) != 0)) + { + const char *key_id_primary; + + len = strlen (fingerprint_primary); + key_id_primary = (len > 16) ? fingerprint_primary + len - 16 : + fingerprint_primary; + + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + + g_string_append_printf (output_buffer, + "Primary key ID %s\n", key_id_primary); + } + + if (exp_timestamp > 0) + append_expire_info (output_buffer, line_prefix, "Signature", exp_timestamp, + sig_expired); + if (key_exp_timestamp > 0) + append_expire_info (output_buffer, line_prefix, "Key", key_exp_timestamp, + key_expired); + if (key_exp_timestamp_primary > 0 && (g_strcmp0 (fingerprint, fingerprint_primary) != 0)) + append_expire_info (output_buffer, line_prefix, "Primary key", + key_exp_timestamp_primary, key_expired); +} + +/** + * ostree_gpg_verify_result_require_valid_signature: + * @result: (nullable): an #OstreeGpgVerifyResult + * @error: A #GError + * + * Checks if the result contains at least one signature from the + * trusted keyring. You can call this function immediately after + * ostree_repo_verify_summary() or ostree_repo_verify_commit_ext() - + * it will handle the %NULL @result and filled @error too. + * + * Returns: %TRUE if @result was not %NULL and had at least one + * signature from trusted keyring, otherwise %FALSE + * + * Since: 2016.6 + */ +gboolean +ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result, + GError **error) +{ + if (result == NULL) + return FALSE; + + if (ostree_gpg_verify_result_count_valid (result) == 0) + { + /* + * Join the description of each failed signature for the error message. + * Only one error code can be returned, so if there was more than one + * signature, use the error of the last one under the assumption that + * it's the most recent and hopefully most likely to be made with a + * valid key. + */ + gint code = OSTREE_GPG_ERROR_NO_SIGNATURE; + g_autoptr(GString) buffer = g_string_sized_new (256); + guint nsigs = ostree_gpg_verify_result_count_all (result); + + if (nsigs == 0) + /* In case an empty result was passed in */ + g_string_append (buffer, "No GPG signatures found"); + else + { + for (int i = nsigs - 1; i >= 0; i--) + { + g_autoptr(GVariant) info = ostree_gpg_verify_result_get_all (result, i); + ostree_gpg_verify_result_describe_variant (info, buffer, "", + OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT); + + if (i == nsigs - 1) + { + gboolean key_missing, key_revoked, key_expired, sig_expired; + g_variant_get_child (info, OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING, + "b", &key_missing); + g_variant_get_child (info, OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED, + "b", &key_revoked); + g_variant_get_child (info, OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED, + "b", &key_expired); + g_variant_get_child (info, OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED, + "b", &sig_expired); + + if (key_missing) + code = OSTREE_GPG_ERROR_MISSING_KEY; + else if (key_revoked) + code = OSTREE_GPG_ERROR_REVOKED_KEY; + else if (key_expired) + code = OSTREE_GPG_ERROR_EXPIRED_KEY; + else if (sig_expired) + code = OSTREE_GPG_ERROR_EXPIRED_SIGNATURE; + else + /* Assume any other issue is a bad signature */ + code = OSTREE_GPG_ERROR_INVALID_SIGNATURE; + } + } + } + + /* Strip any trailing newlines */ + g_strchomp (buffer->str); + g_set_error_literal (error, OSTREE_GPG_ERROR, code, buffer->str); + return FALSE; + } + + return TRUE; +} + +G_DEFINE_QUARK (OstreeGpgError, ostree_gpg_error) diff --git a/src/libostree/ostree-gpg-verify-result.h b/src/libostree/ostree-gpg-verify-result.h new file mode 100644 index 0000000..8f243fc --- /dev/null +++ b/src/libostree/ostree-gpg-verify-result.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_GPG_VERIFY_RESULT \ + (ostree_gpg_verify_result_get_type ()) +#define OSTREE_GPG_VERIFY_RESULT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_GPG_VERIFY_RESULT, OstreeGpgVerifyResult)) +#define OSTREE_IS_GPG_VERIFY_RESULT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_GPG_VERIFY_RESULT)) + +typedef struct OstreeGpgVerifyResult OstreeGpgVerifyResult; + +/** + * OstreeGpgSignatureAttr: + * @OSTREE_GPG_SIGNATURE_ATTR_VALID: + * [#G_VARIANT_TYPE_BOOLEAN] Is the signature valid? + * @OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED: + * [#G_VARIANT_TYPE_BOOLEAN] Has the signature expired? + * @OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED: + * [#G_VARIANT_TYPE_BOOLEAN] Has the signing key expired? + * @OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED: + * [#G_VARIANT_TYPE_BOOLEAN] Has the signing key been revoked? + * @OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING: + * [#G_VARIANT_TYPE_BOOLEAN] Is the signing key missing? + * @OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT: + * [#G_VARIANT_TYPE_STRING] Fingerprint of the signing key + * @OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP: + * [#G_VARIANT_TYPE_INT64] Signature creation Unix timestamp + * @OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP: + * [#G_VARIANT_TYPE_INT64] Signature expiration Unix timestamp (0 if no + * expiration) + * @OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME: + * [#G_VARIANT_TYPE_STRING] Name of the public key algorithm used to create + * the signature + * @OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME: + * [#G_VARIANT_TYPE_STRING] Name of the hash algorithm used to create the + * signature + * @OSTREE_GPG_SIGNATURE_ATTR_USER_NAME: + * [#G_VARIANT_TYPE_STRING] The name of the signing key's primary user + * @OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL: + * [#G_VARIANT_TYPE_STRING] The email address of the signing key's primary + * user + * @OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY: + * [#G_VARIANT_TYPE_STRING] Fingerprint of the signing key's primary key + * (will be the same as OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT if the + * the signature is already from the primary key rather than a subkey, + * and will be the empty string if the key is missing.) + * @OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP: + * [#G_VARIANT_TYPE_INT64] Key expiration Unix timestamp (0 if no + * expiration or if the key is missing) + * @OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP_PRIMARY: + * [#G_VARIANT_TYPE_INT64] Key expiration Unix timestamp of the signing key's + * primary key (will be the same as OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP + * if the signing key is the primary key and 0 if no expiration or if the key + * is missing) + * + * Signature attributes available from an #OstreeGpgVerifyResult. + * The attribute's #GVariantType is shown in brackets. + **/ +typedef enum { + OSTREE_GPG_SIGNATURE_ATTR_VALID, + OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED, + OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED, + OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED, + OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING, + OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT, + OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP, + OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP, + OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, + OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME, + OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, + OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, + OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY, + OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP, + OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP_PRIMARY, +} OstreeGpgSignatureAttr; + +_OSTREE_PUBLIC +GType ostree_gpg_verify_result_get_type (void); + +_OSTREE_PUBLIC +guint ostree_gpg_verify_result_count_all (OstreeGpgVerifyResult *result); + +_OSTREE_PUBLIC +guint ostree_gpg_verify_result_count_valid (OstreeGpgVerifyResult *result); + +_OSTREE_PUBLIC +gboolean ostree_gpg_verify_result_lookup (OstreeGpgVerifyResult *result, + const gchar *key_id, + guint *out_signature_index); + +_OSTREE_PUBLIC +GVariant * ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, + guint signature_index, + OstreeGpgSignatureAttr *attrs, + guint n_attrs); + +_OSTREE_PUBLIC +GVariant * ostree_gpg_verify_result_get_all (OstreeGpgVerifyResult *result, + guint signature_index); + +/** + * OstreeGpgSignatureFormatFlags: + * @OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT: + * Use the default output format + * + * Formatting flags for ostree_gpg_verify_result_describe(). Currently + * there's only one possible output format, but this enumeration allows + * for future variations. + **/ +typedef enum { + OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT = (0 << 0), +} OstreeGpgSignatureFormatFlags; + +_OSTREE_PUBLIC +void ostree_gpg_verify_result_describe (OstreeGpgVerifyResult *result, + guint signature_index, + GString *output_buffer, + const gchar *line_prefix, + OstreeGpgSignatureFormatFlags flags); + +_OSTREE_PUBLIC +void ostree_gpg_verify_result_describe_variant (GVariant *variant, + GString *output_buffer, + const gchar *line_prefix, + OstreeGpgSignatureFormatFlags flags); + +_OSTREE_PUBLIC +gboolean ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result, + GError **error); + +/** + * OstreeGpgError: + * @OSTREE_GPG_ERROR_NO_SIGNATURE: A signature was expected, but not found. + * @OSTREE_GPG_ERROR_INVALID_SIGNATURE: A signature was malformed. + * @OSTREE_GPG_ERROR_MISSING_KEY: A signature was found, but was created with a key not in the configured keyrings. + * @OSTREE_GPG_ERROR_EXPIRED_SIGNATURE: A signature was expired. Since: 2020.1. + * @OSTREE_GPG_ERROR_EXPIRED_KEY: A signature was found, but the key used to + * sign it has expired. Since: 2020.1. + * @OSTREE_GPG_ERROR_REVOKED_KEY: A signature was found, but the key used to + * sign it has been revoked. Since: 2020.1. + * + * Errors returned by signature creation and verification operations in OSTree. + * These may be returned by any API which creates or verifies signatures. + * + * Since: 2017.10 + */ +typedef enum { + OSTREE_GPG_ERROR_NO_SIGNATURE = 0, + OSTREE_GPG_ERROR_INVALID_SIGNATURE, + OSTREE_GPG_ERROR_MISSING_KEY, + OSTREE_GPG_ERROR_EXPIRED_SIGNATURE, + OSTREE_GPG_ERROR_EXPIRED_KEY, + OSTREE_GPG_ERROR_REVOKED_KEY, +} OstreeGpgError; + +/** + * ostree_gpg_error_quark: + * + * Since: 2017.10 + */ +_OSTREE_PUBLIC +GQuark ostree_gpg_error_quark (void); +#define OSTREE_GPG_ERROR (ostree_gpg_error_quark ()) + +G_END_DECLS diff --git a/src/libostree/ostree-impl-system-generator.c b/src/libostree/ostree-impl-system-generator.c new file mode 100644 index 0000000..cb9170b --- /dev/null +++ b/src/libostree/ostree-impl-system-generator.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2017 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#ifdef HAVE_LIBMOUNT +#include +#endif +#include +#include +#include "otutil.h" + +#include "ostree.h" +#include "ostree-core-private.h" +#include "ostree-cmdprivate.h" + +#ifdef HAVE_LIBMOUNT +typedef FILE OtLibMountFile; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtLibMountFile, endmntent) + +/* Taken from systemd path-util.c */ +static bool +is_path (const char *p) +{ + return !!strchr (p, '/'); +} + +/* Taken from systemd path-util.c */ +static char* +path_kill_slashes (char *path) +{ + char *f, *t; + bool slash = false; + + /* Removes redundant inner and trailing slashes. Modifies the + * passed string in-place. + * + * For example: ///foo///bar/ becomes /foo/bar + */ + + for (f = path, t = path; *f; f++) + { + if (*f == '/') + { + slash = true; + continue; + } + + if (slash) + { + slash = false; + *(t++) = '/'; + } + + *(t++) = *f; + } + + /* Special rule, if we are talking of the root directory, a + trailing slash is good */ + + if (t == path && slash) + *(t++) = '/'; + + *t = 0; + return path; +} + +/* Written by ostree-sysroot-deploy.c. We parse out the stateroot here since we + * need to know it to mount /var. Unfortunately we can't easily use the + * libostree API to find the booted deployment since /boot might not have been + * mounted yet. + */ +static char * +stateroot_from_ostree_cmdline (const char *ostree_cmdline, + GError **error) +{ + static GRegex *regex; + static gsize regex_initialized; + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^/ostree/boot.[01]/([^/]+)/", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + g_autoptr(GMatchInfo) match = NULL; + if (!g_regex_match (regex, ostree_cmdline, 0, &match)) + return glnx_null_throw (error, "Failed to parse %s", ostree_cmdline); + + return g_match_info_fetch (match, 1); +} +#endif + +/* Implementation of ostree-system-generator */ +gboolean +_ostree_impl_system_generator (const char *ostree_cmdline, + const char *normal_dir, + const char *early_dir, + const char *late_dir, + GError **error) +{ +#ifdef HAVE_LIBMOUNT + /* Not currently cancellable, but define a var in case we care later */ + GCancellable *cancellable = NULL; + /* Some path constants to avoid typos */ + static const char fstab_path[] = "/etc/fstab"; + static const char var_path[] = "/var"; + + /* ostree-prepare-root was patched to write the stateroot to this file */ + g_autofree char *stateroot = stateroot_from_ostree_cmdline (ostree_cmdline, error); + if (!stateroot) + return FALSE; + + /* Load /etc/fstab if it exists, and look for a /var mount */ + g_autoptr(OtLibMountFile) fstab = setmntent (fstab_path, "re"); + gboolean found_var_mnt = FALSE; + if (!fstab) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "Reading %s", fstab_path); + } + else + { + /* Parse it */ + struct mntent *me; + while ((me = getmntent (fstab))) + { + g_autofree char *where = g_strdup (me->mnt_dir); + if (is_path (where)) + path_kill_slashes (where); + + /* We're only looking for /var here */ + if (strcmp (where, var_path) != 0) + continue; + + found_var_mnt = TRUE; + break; + } + } + + /* If we found /var, we're done */ + if (found_var_mnt) + return TRUE; + + /* Prepare to write to the output unit dir; we use the "normal" dir + * that overrides /usr, but not /etc. + */ + glnx_autofd int normal_dir_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, normal_dir, TRUE, &normal_dir_dfd, error)) + return FALSE; + + /* Generate our bind mount unit */ + const char *stateroot_var_path = glnx_strjoina ("/sysroot/ostree/deploy/", stateroot, "/var"); + + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (normal_dir_dfd, ".", O_WRONLY | O_CLOEXEC, + &tmpf, error)) + return FALSE; + g_autoptr(GOutputStream) outstream = g_unix_output_stream_new (tmpf.fd, FALSE); + gsize bytes_written; + /* This code is inspired by systemd's fstab-generator.c. + * + * Note that our unit doesn't run if systemd.volatile is enabled; + * see https://github.com/ostreedev/ostree/pull/856 + */ + if (!g_output_stream_printf (outstream, &bytes_written, cancellable, error, + "##\n# Automatically generated by ostree-system-generator\n##\n\n" + "[Unit]\n" + "Documentation=man:ostree(1)\n" + "ConditionKernelCommandLine=!systemd.volatile\n" + "Before=local-fs.target\n" + "\n" + "[Mount]\n" + "Where=%s\n" + "What=%s\n" + "Options=bind\n", + var_path, + stateroot_var_path)) + return FALSE; + if (!g_output_stream_flush (outstream, cancellable, error)) + return FALSE; + g_clear_object (&outstream); + /* It should be readable */ + if (!glnx_fchmod (tmpf.fd, 0644, error)) + return FALSE; + /* Error out if somehow it already exists, that'll help us debug conflicts */ + if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_NOREPLACE, + normal_dir_dfd, "var.mount", error)) + return FALSE; + + /* And ensure it's required; newer systemd will auto-inject fs dependencies + * via RequiresMountsFor and the like, but on older versions (e.g. CentOS) we + * need this. It's what the fstab generator does. And my mother always said, + * listen to the fstab generator. + */ + if (!glnx_shutil_mkdir_p_at (normal_dir_dfd, "local-fs.target.requires", 0755, cancellable, error)) + return FALSE; + if (symlinkat ("../var.mount", normal_dir_dfd, "local-fs.target.requires/var.mount") < 0) + return glnx_throw_errno_prefix (error, "symlinkat"); + + return TRUE; +#else + return glnx_throw (error, "Not implemented"); +#endif +} diff --git a/src/libostree/ostree-kernel-args.c b/src/libostree/ostree-kernel-args.c new file mode 100644 index 0000000..c630082 --- /dev/null +++ b/src/libostree/ostree-kernel-args.c @@ -0,0 +1,808 @@ +/* + * Copyright (C) 2013,2014 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-kernel-args.h" +#include "libglnx.h" +#include "otutil.h" + +#include + +struct _OstreeKernelArgs { + GPtrArray *order; + GHashTable *table; +}; + +struct _OstreeKernelArgsEntry { + char *key; + char *value; +}; + +char * +_ostree_kernel_args_entry_get_key (const OstreeKernelArgsEntry *e) +{ + return e->key; +} + +char * +_ostree_kernel_args_entry_get_value (const OstreeKernelArgsEntry *e) +{ + return e->value; +} + +void +_ostree_kernel_args_entry_set_key (OstreeKernelArgsEntry *e, + char *key) +{ + e->key = key; +} + +void +_ostree_kernel_args_entry_set_value (OstreeKernelArgsEntry *e, + char *value) +{ + e->value = value; +} + +char * +_ostree_kernel_args_get_key_index (const OstreeKernelArgs *kargs, + int i) +{ + OstreeKernelArgsEntry *e = kargs->order->pdata[i]; + return e->key; +} + +char * +_ostree_kernel_args_get_value_index (const OstreeKernelArgs *kargs, + int i) +{ + OstreeKernelArgsEntry *e = kargs->order->pdata[i]; + return e->value; +} + +OstreeKernelArgsEntry * +_ostree_kernel_args_entry_new (void) +{ + return g_new0 (OstreeKernelArgsEntry, 1); +} + +void +_ostree_kernel_args_entry_value_free (OstreeKernelArgsEntry *e) +{ + g_clear_pointer (&e->value, g_free); +} + +/* Free the value field, and the entry. This should be set as the free + * function, for all pointer arrays stored in the hash table. + */ +static void +kernel_args_entry_free_from_table (gpointer data) +{ + OstreeKernelArgsEntry *e = data; + // The hash table owns the key; do not free it here. + g_free (_ostree_kernel_args_entry_get_value (e)); + g_free (e); +} + +static gboolean +kernel_args_entry_value_equal (gconstpointer data, + gconstpointer value) +{ + const OstreeKernelArgsEntry *e = data; + return g_strcmp0 (_ostree_kernel_args_entry_get_value (e), value) == 0; +} + +static gboolean +kernel_args_entry_key_equal (gconstpointer data, + gconstpointer key) +{ + const OstreeKernelArgsEntry *e = data; + return g_strcmp0 (_ostree_kernel_args_entry_get_key (e), key) == 0; +} + +static void +kernel_args_entry_replace_value (OstreeKernelArgsEntry *e, + const char *value) +{ + g_assert (e); + _ostree_kernel_args_entry_value_free (e); + _ostree_kernel_args_entry_set_value (e, g_strdup (value)); +} + +static void +kernel_args_remove_entries_from_order (GPtrArray *order, + GPtrArray *entries) +{ + g_assert (entries); + for (int i = 0; i < entries->len; i++) + g_assert (g_ptr_array_remove (order, entries->pdata[i])); +} + +static char * +split_keyeq (char *arg) +{ + char *eq; + + eq = strchr (arg, '='); + if (eq == NULL) + return NULL; + + // Note: key/val are in a single allocation block, so we don't free val. + *eq = '\0'; + return eq+1; +} + +static gboolean +_arg_has_prefix (const char *arg, + char **prefixes) +{ + char **strviter; + + for (strviter = prefixes; strviter && *strviter; strviter++) + { + const char *prefix = *strviter; + + if (g_str_has_prefix (arg, prefix)) + return TRUE; + } + + return FALSE; +} + +static gboolean +strcmp0_equal (gconstpointer v1, + gconstpointer v2) +{ + return g_strcmp0 (v1, v2) == 0; +} + +/** + * ostree_kernel_args_new: (skip) + * + * Initializes a new OstreeKernelArgs structure and returns it + * + * Returns: (transfer full): A newly created #OstreeKernelArgs for kernel arguments + * + * Since: 2019.3 + **/ +OstreeKernelArgs * +ostree_kernel_args_new (void) +{ + OstreeKernelArgs *ret; + ret = g_new0 (OstreeKernelArgs, 1); + /* Hash table owns the kernel args entries, since it uses keys to index, + * and its values are used to locate entries in the order array. */ + ret->table = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify)g_ptr_array_unref); + ret->order = g_ptr_array_new_with_free_func (NULL); + return ret; +} + +/** + * ostree_kernel_args_free: + * @kargs: An OstreeKernelArgs that represents kernel arguments + * + * Frees the kargs structure + * + * Since: 2019.3 + **/ +void +ostree_kernel_args_free (OstreeKernelArgs *kargs) +{ + if (!kargs) + return; + g_ptr_array_unref (kargs->order); + g_hash_table_unref (kargs->table); + g_free (kargs); +} + +/** + * ostree_kernel_args_cleanup: + * @loc: Address of an OstreeKernelArgs pointer + * + * Frees the OstreeKernelArgs structure pointed by *loc + * + * Since: 2019.3 + **/ +void +ostree_kernel_args_cleanup (void *loc) +{ + ostree_kernel_args_free (*((OstreeKernelArgs**)loc)); +} + +/** + * _ostree_kernel_arg_get_kargs_table: + * @kargs: An OstreeKernelArgs that represents kernel arguments + * + * Returns: (transfer none): #GHashTable that associates with the @kargs + * + * Note: this function is private for now, since the data structures underneath might be changed + * + * Since: 2019.3 + **/ +GHashTable* +_ostree_kernel_arg_get_kargs_table (OstreeKernelArgs *kargs) +{ + if (kargs != NULL) + return kargs->table; + return NULL; +} + +/** + * _ostree_kernel_arg_get_key_array: + * @kargs: An OstreeKernelArgs that represents kernel arguments + * + * Returns: (transfer none) (element-type utf8): #GPtrArray that associates with @kargs + * + * Note: this function is private for now, since the data structures underneath might be changed + * + * Since: 2019.3 + **/ +GPtrArray* +_ostree_kernel_arg_get_key_array (OstreeKernelArgs *kargs) +{ + if (kargs != NULL) + return kargs->order; + return NULL; +} + +/** + * ostree_kernel_args_new_replace: + * @kargs: OstreeKernelArgs instance + * @arg: a string argument + * @error: error instance + * + * This function implements the basic logic behind key/value pair + * replacement. Do note that the arg need to be properly formatted + * + * When replacing key with exact one value, the arg can be in + * the form: + * key, key=new_val, or key=old_val=new_val + * The first one swaps the old_val with the key to an empty value + * The second and third replace the old_val into the new_val + * + * When replacing key with multiple values, the arg can only be + * in the form of: + * key=old_val=new_val. Unless there is a special case where + * there is an empty value associated with the key, then + * key=new_val will work because old_val is empty. The empty + * val will be swapped with the new_val in that case + * + * Returns: %TRUE on success, %FALSE on failure (and in some other instances such as: + * 1. key not found in @kargs + * 2. old value not found when @arg is in the form of key=old_val=new_val + * 3. multiple old values found when @arg is in the form of key=old_val) + * + * Since: 2019.3 + **/ +gboolean +ostree_kernel_args_new_replace (OstreeKernelArgs *kargs, + const char *arg, + GError **error) +{ + g_autofree char *arg_owned = g_strdup (arg); + const char *key = arg_owned; + const char *val = split_keyeq (arg_owned); + + GPtrArray *entries = g_hash_table_lookup (kargs->table, key); + if (!entries) + return glnx_throw (error, "No key '%s' found", key); + g_assert_cmpuint (entries->len, >, 0); + + /* first handle the case where the user just wants to replace an old value */ + if (val && strchr (val, '=')) + { + g_autofree char *old_val = g_strdup (val); + const char *new_val = split_keyeq (old_val); + g_assert (new_val); + + guint i = 0; + if (!ot_ptr_array_find_with_equal_func (entries, old_val, kernel_args_entry_value_equal, &i)) + return glnx_throw (error, "No karg '%s=%s' found", key, old_val); + + kernel_args_entry_replace_value (entries->pdata[i], new_val); + return TRUE; + } + + /* can't know which val to replace without the old_val=new_val syntax */ + if (entries->len > 1) + return glnx_throw (error, "Multiple values for key '%s' found", key); + + kernel_args_entry_replace_value (entries->pdata[0], val); + return TRUE; +} + +/** + * ostree_kernel_args_delete_key_entry + * @kargs: an OstreeKernelArgs instance + * @key: the key to remove + * @error: an GError instance + * + * This function removes the key entry from the hashtable + * as well from the order pointer array inside kargs + * + * Note: since both table and order inside kernel args + * are with free function, no extra free functions are + * being called as they are done automatically by GLib + * + * Returns: %TRUE on success, %FALSE on failure + * + * Since: 2019.3 + **/ +gboolean +ostree_kernel_args_delete_key_entry (OstreeKernelArgs *kargs, + const char *key, + GError **error) +{ + GPtrArray *entries = g_hash_table_lookup (kargs->table, key); + if (!entries) + return glnx_throw (error, "No key '%s' found", key); + g_assert_cmpuint (entries->len, >, 0); + + kernel_args_remove_entries_from_order (kargs->order, entries); + + if (!g_hash_table_remove (kargs->table, key)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to find kernel argument '%s'", + key); + return FALSE; + } + + return TRUE; +} + +/** + * ostree_kernel_args_delete: + * @kargs: a OstreeKernelArgs instance + * @arg: key or key/value pair for deletion + * @error: an GError instance + * + * There are few scenarios being handled for deletion: + * + * 1: for input arg with a single key(i.e without = for split), + * the key/value pair will be deleted if there is only + * one value that is associated with the key + * + * 2: for input arg wth key/value pair, the specific key + * value pair will be deleted from the pointer array + * if those exist. + * + * 3: If the found key has only one value + * associated with it, the key entry in the table will also + * be removed, and the key will be removed from order table + * + * Returns: %TRUE on success, %FALSE on failure + * + * Since: 2019.3 + **/ +gboolean +ostree_kernel_args_delete (OstreeKernelArgs *kargs, + const char *arg, + GError **error) +{ + g_autofree char *arg_owned = g_strdup (arg); + const char *key = arg_owned; + const char *val = split_keyeq (arg_owned); + + GPtrArray *entries = g_hash_table_lookup (kargs->table, key); + if (!entries) + return glnx_throw (error, "No key '%s' found", key); + g_assert_cmpuint (entries->len, >, 0); + + /* special-case: we allow deleting by key only if there's only one val */ + if (entries->len == 1) + { + /* but if a specific val was passed, check that it's the same */ + OstreeKernelArgsEntry *e = entries->pdata[0]; + if (val && !strcmp0_equal (val, _ostree_kernel_args_entry_get_value (e))) + return glnx_throw (error, "No karg '%s=%s' found", key, val); + return ostree_kernel_args_delete_key_entry (kargs, key, error); + } + + /* note val might be NULL here, in which case we're looking for `key`, not `key=` or + * `key=val` */ + guint i = 0; + if (!ot_ptr_array_find_with_equal_func (entries, val, kernel_args_entry_value_equal, &i)) + { + if (!val) + /* didn't find NULL -> only key= key=val1 key=val2 style things left, so the user + * needs to be more specific */ + return glnx_throw (error, "Multiple values for key '%s' found", arg); + return glnx_throw (error, "No karg '%s' found", arg); + } + + g_assert (g_ptr_array_remove (kargs->order, entries->pdata[i])); + g_assert (g_ptr_array_remove_index (entries, i)); + return TRUE; +} + +/** + * ostree_kernel_args_replace_take: + * @kargs: a OstreeKernelArgs instance + * @arg: (transfer full): key or key/value pair for replacement + * + * Finds and replaces the old key if @arg is already in the hash table, + * otherwise adds @arg as new key and split_keyeq (arg) as value. + * Note that when replacing old key, the old values are freed. + * + * Since: 2019.3 + **/ +void +ostree_kernel_args_replace_take (OstreeKernelArgs *kargs, + char *arg) +{ + gboolean existed; + GPtrArray *entries = g_ptr_array_new_with_free_func (kernel_args_entry_free_from_table); + const char *value = split_keyeq (arg); + gpointer old_key; + + OstreeKernelArgsEntry *entry = g_new0 (OstreeKernelArgsEntry, 1); + _ostree_kernel_args_entry_set_value (entry, g_strdup (value)); + g_ptr_array_add (entries, entry); + + gpointer old_entries_ptr; + existed = g_hash_table_lookup_extended (kargs->table, arg, &old_key, &old_entries_ptr); + GPtrArray *old_entries = old_entries_ptr; + + if (existed) + { + g_assert (old_entries); + g_assert_cmpuint (old_entries->len, >, 0); + + guint old_order_index = 0; + g_assert (ot_ptr_array_find_with_equal_func (kargs->order, old_key, kernel_args_entry_key_equal, &old_order_index)); + kernel_args_remove_entries_from_order (kargs->order, old_entries); + + g_assert_cmpstr (old_key, ==, arg); + _ostree_kernel_args_entry_set_key (entry, old_key); + g_ptr_array_insert (kargs->order, old_order_index, entry); + // `arg` is freed by the `g_hash_table_insert` call. + g_hash_table_insert (kargs->table, arg, entries); + } + else + { + _ostree_kernel_args_entry_set_key (entry, arg); + g_hash_table_replace (kargs->table, arg, entries); + g_ptr_array_add (kargs->order, entry); + } +} + +/** + * ostree_kernel_args_replace: + * @kargs: a OstreeKernelArgs instance + * @arg: key or key/value pair for replacement + * + * Finds and replaces the old key if @arg is already in the hash table, + * otherwise adds @arg as new key and split_keyeq (arg) as value. + * Note that when replacing old key value pair, the old values are freed. + * + * Since: 2019.3 + **/ +void +ostree_kernel_args_replace (OstreeKernelArgs *kargs, + const char *arg) +{ + ostree_kernel_args_replace_take (kargs, g_strdup (arg)); +} + +/** + * ostree_kernel_args_append: + * @kargs: a OstreeKernelArgs instance + * @arg: key or key/value pair to be added + * + * Appends @arg which is in the form of key=value pair to the hash table kargs->table + * (appends to the value list if key is already in the hash table) + * and appends key to kargs->order if it is not in the hash table already. + * + * Since: 2019.3 + **/ +void +ostree_kernel_args_append (OstreeKernelArgs *kargs, + const char *arg) +{ + gboolean existed = TRUE; + GPtrArray *entries = NULL; + char *duped = g_strdup (arg); + const char *val = split_keyeq (duped); + + entries = g_hash_table_lookup (kargs->table, duped); + if (!entries) + { + entries = g_ptr_array_new_with_free_func (kernel_args_entry_free_from_table); + existed = FALSE; + } + + OstreeKernelArgsEntry *entry = _ostree_kernel_args_entry_new (); + _ostree_kernel_args_entry_set_key (entry, duped); + _ostree_kernel_args_entry_set_value (entry, g_strdup (val)); + + g_ptr_array_add (entries, entry); + g_ptr_array_add (kargs->order, entry); + + if (!existed) + g_hash_table_replace (kargs->table, duped, entries); +} + +/** + * ostree_kernel_args_replace_argv: + * @kargs: a OstreeKernelArgs instance + * @argv: an array of key or key/value pairs + * + * Finds and replaces each non-null arguments of @argv in the hash table, + * otherwise adds individual arg as new key and split_keyeq (arg) as value. + * Note that when replacing old key value pair, the old values are freed. + * + * Since: 2019.3 + **/ +void +ostree_kernel_args_replace_argv (OstreeKernelArgs *kargs, + char **argv) +{ + char **strviter; + + for (strviter = argv; strviter && *strviter; strviter++) + { + const char *arg = *strviter; + ostree_kernel_args_replace (kargs, arg); + } +} + +/** + * ostree_kernel_args_append_argv_filtered: + * @kargs: a OstreeKernelArgs instance + * @argv: an array of key=value argument pairs + * @prefixes: an array of prefix strings + * + * Appends each argument that does not have one of the @prefixes as prefix to the @kargs + * + * Since: 2019.3 + **/ +void +ostree_kernel_args_append_argv_filtered (OstreeKernelArgs *kargs, + char **argv, + char **prefixes) +{ + char **strviter; + + for (strviter = argv; strviter && *strviter; strviter++) + { + const char *arg = *strviter; + + if (!_arg_has_prefix (arg, prefixes)) + ostree_kernel_args_append (kargs, arg); + } +} + +/** + * ostree_kernel_args_append_argv: + * @kargs: a OstreeKernelArgs instance + * @argv: an array of key=value argument pairs + * + * Appends each value in @argv to the corresponding value array and + * appends key to kargs->order if it is not in the hash table already. + * + * Since: 2019.3 + **/ +void +ostree_kernel_args_append_argv (OstreeKernelArgs *kargs, + char **argv) +{ + ostree_kernel_args_append_argv_filtered (kargs, argv, NULL); +} + +/** + * ostree_kernel_args_append_proc_cmdline: + * @kargs: a OstreeKernelArgs instance + * @cancellable: optional GCancellable object, NULL to ignore + * @error: an GError instance + * + * Appends the command line arguments in the file "/proc/cmdline" + * that does not have "BOOT_IMAGE=" and "initrd=" as prefixes to the @kargs + * + * Returns: %TRUE on success, %FALSE on failure + * + * Since: 2019.3 + **/ +gboolean +ostree_kernel_args_append_proc_cmdline (OstreeKernelArgs *kargs, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GFile) proc_cmdline_path = g_file_new_for_path ("/proc/cmdline"); + g_autofree char *proc_cmdline = NULL; + gsize proc_cmdline_len = 0; + g_auto(GStrv) proc_cmdline_args = NULL; + /* When updating the filter list don't forget to update the list in the tests + * e.g. tests/test-admin-deploy-karg.sh and + * tests/test-admin-instutil-set-kargs.sh + */ + char *filtered_prefixes[] = { "BOOT_IMAGE=", /* GRUB 2 */ + "initrd=", /* sd-boot */ + NULL }; + + if (!g_file_load_contents (proc_cmdline_path, cancellable, + &proc_cmdline, &proc_cmdline_len, + NULL, error)) + return FALSE; + + g_strchomp (proc_cmdline); + + proc_cmdline_args = g_strsplit (proc_cmdline, " ", -1); + ostree_kernel_args_append_argv_filtered (kargs, proc_cmdline_args, + filtered_prefixes); + + return TRUE; +} + +/** + * ostree_kernel_args_parse_append: + * @kargs: a OstreeKernelArgs instance + * @options: a string representing command line arguments + * + * Parses @options by separating it by whitespaces and appends each argument to @kargs + * + * Since: 2019.3 + **/ +void +ostree_kernel_args_parse_append (OstreeKernelArgs *kargs, + const char *options) +{ + char **args = NULL; + char **iter; + + if (!options) + return; + + args = g_strsplit (options, " ", -1); + for (iter = args; *iter; iter++) + { + char *arg = *iter; + ostree_kernel_args_append (kargs, arg); + } + g_strfreev (args); +} + +/** + * ostree_kernel_args_from_string: (skip) + * @options: a string representing command line arguments + * + * Initializes a new OstreeKernelArgs then parses and appends @options + * to the empty OstreeKernelArgs + * + * Returns: (transfer full): newly allocated #OstreeKernelArgs with @options appended + * + * Since: 2019.3 + **/ +OstreeKernelArgs * +ostree_kernel_args_from_string (const char *options) +{ + OstreeKernelArgs *ret; + + ret = ostree_kernel_args_new (); + ostree_kernel_args_parse_append (ret, options); + + return ret; +} + +/** + * ostree_kernel_args_to_strv: + * @kargs: a OstreeKernelArgs instance + * + * Extracts all key value pairs in @kargs and appends to a temporary + * array in forms of "key=value" or "key" if value is NULL, and returns + * the temporary array with the GPtrArray wrapper freed + * + * Returns: (transfer full): an array of "key=value" pairs or "key" if value is NULL + * + * Since: 2019.3 + **/ +char ** +ostree_kernel_args_to_strv (OstreeKernelArgs *kargs) +{ + GPtrArray *strv = g_ptr_array_new (); + guint i; + + for (i = 0; i < kargs->order->len; i++) + { + const char *key = _ostree_kernel_args_get_key_index (kargs, i); + const char *value = _ostree_kernel_args_get_value_index (kargs, i); + + if (value == NULL) + g_ptr_array_add (strv, g_strconcat (key, NULL)); + else + g_ptr_array_add (strv, g_strconcat (key, "=", value, NULL)); + } + g_ptr_array_add (strv, NULL); + + return (char**)g_ptr_array_free (strv, FALSE); +} + +/** + * ostree_kernel_args_to_string: + * @kargs: a OstreeKernelArgs instance + * + * Extracts all key value pairs in @kargs and appends to a temporary + * GString in forms of "key=value" or "key" if value is NULL separated + * by a single whitespace, and returns the temporary string with the + * GString wrapper freed + * + * Note: the application will be terminated if one of the values array + * in @kargs is NULL + * + * Returns: (transfer full): a string of "key=value" pairs or "key" if value is NULL, + * separated by single whitespaces + * + * Since: 2019.3 + **/ +char * +ostree_kernel_args_to_string (OstreeKernelArgs *kargs) +{ + GString *buf = g_string_new (""); + gboolean first = TRUE; + guint i; + + for (i = 0; i < kargs->order->len; i++) + { + const char *key = _ostree_kernel_args_get_key_index (kargs, i); + const char *value = _ostree_kernel_args_get_value_index (kargs, i); + + if (first) + first = FALSE; + else + g_string_append_c (buf, ' '); + + g_string_append (buf, key); + if (value != NULL) + { + g_string_append_c (buf, '='); + g_string_append (buf, value); + } + } + + return g_string_free (buf, FALSE); +} + +/** + * ostree_kernel_args_get_last_value: + * @kargs: a OstreeKernelArgs instance + * @key: a key to look for in @kargs hash table + * + * Finds and returns the last element of value array + * corresponding to the @key in @kargs hash table. Note that the application + * will be terminated if the @key is found but the value array is empty + * + * Returns: NULL if @key is not found in the @kargs hash table, + * otherwise returns last element of value array corresponding to @key + * + * Since: 2019.3 + **/ +const char * +ostree_kernel_args_get_last_value (OstreeKernelArgs *kargs, const char *key) +{ + const GPtrArray *entries = g_hash_table_lookup (kargs->table, key); + + if (!entries) + return NULL; + + g_assert (entries->len > 0); + const OstreeKernelArgsEntry *e = entries->pdata[entries->len-1]; + return _ostree_kernel_args_entry_get_value (e); +} diff --git a/src/libostree/ostree-kernel-args.h b/src/libostree/ostree-kernel-args.h new file mode 100644 index 0000000..5c8be0c --- /dev/null +++ b/src/libostree/ostree-kernel-args.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2013,2014 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include +#include "ostree-types.h" + +G_BEGIN_DECLS + +typedef struct _OstreeKernelArgs OstreeKernelArgs; +typedef struct _OstreeKernelArgsEntry OstreeKernelArgsEntry; + +GHashTable *_ostree_kernel_arg_get_kargs_table (OstreeKernelArgs *kargs); + +GPtrArray *_ostree_kernel_arg_get_key_array (OstreeKernelArgs *kargs); + +char * +_ostree_kernel_args_entry_get_key (const OstreeKernelArgsEntry *e); + +char * +_ostree_kernel_args_entry_get_value (const OstreeKernelArgsEntry *e); + +void +_ostree_kernel_args_entry_set_key (OstreeKernelArgsEntry *e, + char *key); + +void +_ostree_kernel_args_entry_set_value (OstreeKernelArgsEntry *e, + char *value); + +char * +_ostree_kernel_args_get_key_index (const OstreeKernelArgs *kargs, + int i); + +char * +_ostree_kernel_args_get_value_index (const OstreeKernelArgs *kargs, + int i); + +OstreeKernelArgsEntry * +_ostree_kernel_args_entry_new (void); + +void +_ostree_kernel_args_entry_value_free (OstreeKernelArgsEntry *e); + +_OSTREE_PUBLIC +void ostree_kernel_args_free (OstreeKernelArgs *kargs); + +_OSTREE_PUBLIC +OstreeKernelArgs *ostree_kernel_args_new (void); + +_OSTREE_PUBLIC +void ostree_kernel_args_cleanup (void *loc); + +_OSTREE_PUBLIC +void ostree_kernel_args_replace_take (OstreeKernelArgs *kargs, + char *arg); + +_OSTREE_PUBLIC +void ostree_kernel_args_replace (OstreeKernelArgs *kargs, + const char *arg); + +_OSTREE_PUBLIC +void ostree_kernel_args_replace_argv (OstreeKernelArgs *kargs, + char **argv); + +_OSTREE_PUBLIC +void ostree_kernel_args_append (OstreeKernelArgs *kargs, + const char *arg); + +_OSTREE_PUBLIC +void ostree_kernel_args_append_argv (OstreeKernelArgs *kargs, + char **argv); + +_OSTREE_PUBLIC +void ostree_kernel_args_append_argv_filtered (OstreeKernelArgs *kargs, + char **argv, + char **prefixes); + +_OSTREE_PUBLIC +gboolean ostree_kernel_args_new_replace (OstreeKernelArgs *kargs, + const char *arg, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_kernel_args_delete (OstreeKernelArgs *kargs, + const char *arg, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_kernel_args_delete_key_entry (OstreeKernelArgs *kargs, + const char *key, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_kernel_args_append_proc_cmdline (OstreeKernelArgs *kargs, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_kernel_args_parse_append (OstreeKernelArgs *kargs, + const char *options); + +_OSTREE_PUBLIC +const char *ostree_kernel_args_get_last_value (OstreeKernelArgs *kargs, + const char *key); + +_OSTREE_PUBLIC +OstreeKernelArgs *ostree_kernel_args_from_string (const char *options); + +_OSTREE_PUBLIC +char **ostree_kernel_args_to_strv (OstreeKernelArgs *kargs); + +_OSTREE_PUBLIC +char *ostree_kernel_args_to_string (OstreeKernelArgs *kargs); + +G_END_DECLS diff --git a/src/libostree/ostree-libarchive-input-stream.c b/src/libostree/ostree-libarchive-input-stream.c new file mode 100644 index 0000000..4de05e2 --- /dev/null +++ b/src/libostree/ostree-libarchive-input-stream.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + + +#include +#include +#include "ostree-libarchive-input-stream.h" + +enum { + PROP_0, + PROP_ARCHIVE +}; + +G_DEFINE_TYPE (OstreeLibarchiveInputStream, _ostree_libarchive_input_stream, G_TYPE_INPUT_STREAM) + +struct _OstreeLibarchiveInputStreamPrivate { + struct archive *archive; +}; + +static void ostree_libarchive_input_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ostree_libarchive_input_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static gssize ostree_libarchive_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error); +static gboolean ostree_libarchive_input_stream_close (GInputStream *stream, + GCancellable *cancellable, + GError **error); + +static void +ostree_libarchive_input_stream_finalize (GObject *object) +{ + G_OBJECT_CLASS (_ostree_libarchive_input_stream_parent_class)->finalize (object); +} + +static void +_ostree_libarchive_input_stream_class_init (OstreeLibarchiveInputStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (OstreeLibarchiveInputStreamPrivate)); + + gobject_class->get_property = ostree_libarchive_input_stream_get_property; + gobject_class->set_property = ostree_libarchive_input_stream_set_property; + gobject_class->finalize = ostree_libarchive_input_stream_finalize; + + stream_class->read_fn = ostree_libarchive_input_stream_read; + stream_class->close_fn = ostree_libarchive_input_stream_close; + + /** + * OstreeLibarchiveInputStream:archive: + * + * The archive that the stream reads from. + */ + g_object_class_install_property (gobject_class, + PROP_ARCHIVE, + g_param_spec_pointer ("archive", + "", "", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + +} + +static void +ostree_libarchive_input_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeLibarchiveInputStream *self; + + self = OSTREE_LIBARCHIVE_INPUT_STREAM (object); + + switch (prop_id) + { + case PROP_ARCHIVE: + self->priv->archive = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_libarchive_input_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeLibarchiveInputStream *self; + + self = OSTREE_LIBARCHIVE_INPUT_STREAM (object); + + switch (prop_id) + { + case PROP_ARCHIVE: + g_value_set_pointer (value, self->priv->archive); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +_ostree_libarchive_input_stream_init (OstreeLibarchiveInputStream *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + OSTREE_TYPE_LIBARCHIVE_INPUT_STREAM, + OstreeLibarchiveInputStreamPrivate); + +} + +GInputStream * +_ostree_libarchive_input_stream_new (struct archive *a) +{ + OstreeLibarchiveInputStream *stream; + + stream = g_object_new (OSTREE_TYPE_LIBARCHIVE_INPUT_STREAM, + "archive", a, + NULL); + + return G_INPUT_STREAM (stream); +} + +static gssize +ostree_libarchive_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + OstreeLibarchiveInputStream *self; + gssize res = -1; + + self = OSTREE_LIBARCHIVE_INPUT_STREAM (stream); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + + res = archive_read_data (self->priv->archive, buffer, count); + if (res < 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", archive_error_string (self->priv->archive)); + } + + return res; +} + +static gboolean +ostree_libarchive_input_stream_close (GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + return TRUE; +} diff --git a/src/libostree/ostree-libarchive-input-stream.h b/src/libostree/ostree-libarchive-input-stream.h new file mode 100644 index 0000000..4d1937f --- /dev/null +++ b/src/libostree/ostree-libarchive-input-stream.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + */ + +#pragma once + +#include +#include "ostree-libarchive-private.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_LIBARCHIVE_INPUT_STREAM (_ostree_libarchive_input_stream_get_type ()) +#define OSTREE_LIBARCHIVE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_LIBARCHIVE_INPUT_STREAM, OstreeLibarchiveInputStream)) +#define OSTREE_LIBARCHIVE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_LIBARCHIVE_INPUT_STREAM, OstreeLibarchiveInputStreamClass)) +#define OSTREE_IS_LIBARCHIVE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_LIBARCHIVE_INPUT_STREAM)) +#define OSTREE_IS_LIBARCHIVE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_LIBARCHIVE_INPUT_STREAM)) +#define OSTREE_LIBARCHIVE_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_LIBARCHIVE_INPUT_STREAM, OstreeLibarchiveInputStreamClass)) + +typedef struct _OstreeLibarchiveInputStream OstreeLibarchiveInputStream; +typedef struct _OstreeLibarchiveInputStreamClass OstreeLibarchiveInputStreamClass; +typedef struct _OstreeLibarchiveInputStreamPrivate OstreeLibarchiveInputStreamPrivate; + +struct _OstreeLibarchiveInputStream +{ + GInputStream parent_instance; + + /*< private >*/ + OstreeLibarchiveInputStreamPrivate *priv; +}; + +struct _OstreeLibarchiveInputStreamClass +{ + GInputStreamClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + void (*_g_reserved1) (void); + void (*_g_reserved2) (void); + void (*_g_reserved3) (void); + void (*_g_reserved4) (void); + void (*_g_reserved5) (void); +}; + +GType _ostree_libarchive_input_stream_get_type (void) G_GNUC_CONST; + +GInputStream * _ostree_libarchive_input_stream_new (struct archive *a); + +G_END_DECLS diff --git a/src/libostree/ostree-libarchive-private.h b/src/libostree/ostree-libarchive-private.h new file mode 100644 index 0000000..46da3e1 --- /dev/null +++ b/src/libostree/ostree-libarchive-private.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + */ + +#pragma once + +/* Private, not for introspection */ +#ifndef __GI_SCANNER__ + +#include "config.h" + +#include +#include "otutil.h" +#ifdef HAVE_LIBARCHIVE +#include +#include +#endif + +G_BEGIN_DECLS + +#ifdef HAVE_LIBARCHIVE +typedef struct archive OtAutoArchiveWrite; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveWrite, archive_write_free) +typedef struct archive OtAutoArchiveRead; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveRead, archive_read_free) + +static inline OtAutoArchiveRead * +ot_archive_read_new (void) +{ + OtAutoArchiveRead *a = archive_read_new (); + +#ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL + archive_read_support_filter_all (a); +#else + archive_read_support_compression_all (a); +#endif + archive_read_support_format_all (a); + + return a; +} + +static inline OtAutoArchiveRead * +ot_open_archive_read (const char *path, GError **error) +{ + g_autoptr(OtAutoArchiveRead) a = ot_archive_read_new (); + + if (archive_read_open_filename (a, path, 8192) != ARCHIVE_OK) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "archive_read_open_filename: %s", archive_error_string (a)); + return NULL; + } + + return g_steal_pointer (&a); +} + +static inline OtAutoArchiveRead * +ot_open_archive_read_fd (int fd, GError **error) +{ + g_autoptr(OtAutoArchiveRead) a = ot_archive_read_new (); + + if (archive_read_open_fd (a, fd, 8192) != ARCHIVE_OK) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "archive_read_open_fd: %s", archive_error_string (a)); + return NULL; + } + + return g_steal_pointer (&a); +} + +#endif + +G_END_DECLS + +#endif diff --git a/src/libostree/ostree-linuxfsutil.c b/src/libostree/ostree-linuxfsutil.c new file mode 100644 index 0000000..231ecf7 --- /dev/null +++ b/src/libostree/ostree-linuxfsutil.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-linuxfsutil.h" +#include "otutil.h" + +#include +#include +#include + +#include "otutil.h" + +/** + * _ostree_linuxfs_fd_alter_immutable_flag: + * @fd: A file descriptor + * @new_immutable_state: Set this to %TRUE to make the file immutable, %FALSE to unset the flag + * @cancellable: Cancellable + * @error: GError + * + * Alter the immutable flag of object referred to by @fd; may be a + * regular file or a directory. + * + * If the operation is not supported by the underlying filesystem, or + * we are running without sufficient privileges, this function will + * silently do nothing. + */ +gboolean +_ostree_linuxfs_fd_alter_immutable_flag (int fd, + gboolean new_immutable_state, + GCancellable *cancellable, + GError **error) +{ + static gint no_alter_immutable = 0; + + if (g_atomic_int_get (&no_alter_immutable)) + return TRUE; + + unsigned long flags; + int r = ioctl (fd, EXT2_IOC_GETFLAGS, &flags); + if (r == -1) + { + if (errno == EPERM) + g_atomic_int_set (&no_alter_immutable, 1); + else if (errno == EOPNOTSUPP || errno == ENOTTY) + ; + else + return glnx_throw_errno_prefix (error, "ioctl(EXT2_IOC_GETFLAGS)"); + } + else + { + gboolean prev_immutable_state = (flags & EXT2_IMMUTABLE_FL) > 0; + if (prev_immutable_state == new_immutable_state) + return TRUE; /* Nothing to do */ + + if (new_immutable_state) + flags |= EXT2_IMMUTABLE_FL; + else + flags &= ~EXT2_IMMUTABLE_FL; + r = ioctl (fd, EXT2_IOC_SETFLAGS, &flags); + if (r == -1) + { + if (errno == EPERM) + g_atomic_int_set (&no_alter_immutable, 1); + else if (errno == EOPNOTSUPP || errno == ENOTTY) + ; + else + return glnx_throw_errno_prefix (error, "ioctl(EXT2_IOC_SETFLAGS)"); + } + } + + return TRUE; +} diff --git a/src/libostree/ostree-linuxfsutil.h b/src/libostree/ostree-linuxfsutil.h new file mode 100644 index 0000000..c996461 --- /dev/null +++ b/src/libostree/ostree-linuxfsutil.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-types.h" + +G_BEGIN_DECLS + +gboolean +_ostree_linuxfs_fd_alter_immutable_flag (int fd, + gboolean new_immutable_state, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-lzma-common.c b/src/libostree/ostree-lzma-common.c new file mode 100644 index 0000000..d4bc71b --- /dev/null +++ b/src/libostree/ostree-lzma-common.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "ostree-lzma-common.h" + +#include +#include +#include + +GConverterResult +_ostree_lzma_return (lzma_ret res, + GError **error) +{ + switch (res) + { + case LZMA_OK: + return G_CONVERTER_CONVERTED; + case LZMA_STREAM_END: + return G_CONVERTER_FINISHED; + case LZMA_NO_CHECK: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Stream is corrupt"); + return G_CONVERTER_ERROR; + case LZMA_UNSUPPORTED_CHECK: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot calculate integrity check"); + return G_CONVERTER_ERROR; + case LZMA_MEM_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Out of memory"); + return G_CONVERTER_ERROR; + case LZMA_MEMLIMIT_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Exceeded memory limit"); + return G_CONVERTER_ERROR; + case LZMA_FORMAT_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "File format not recognized"); + return G_CONVERTER_ERROR; + case LZMA_OPTIONS_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid or unsupported options"); + return G_CONVERTER_ERROR; + case LZMA_DATA_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Data is corrupt"); + return G_CONVERTER_ERROR; + case LZMA_BUF_ERROR: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT, + "Input buffer too small"); + return G_CONVERTER_ERROR; + default: + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unrecognized LZMA error"); + return G_CONVERTER_ERROR; + } +} diff --git a/src/libostree/ostree-lzma-common.h b/src/libostree/ostree-lzma-common.h new file mode 100644 index 0000000..ce7cf3a --- /dev/null +++ b/src/libostree/ostree-lzma-common.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +GConverterResult _ostree_lzma_return (lzma_ret value, GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-lzma-compressor.c b/src/libostree/ostree-lzma-compressor.c new file mode 100644 index 0000000..3b20141 --- /dev/null +++ b/src/libostree/ostree-lzma-compressor.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "ostree-lzma-compressor.h" +#include "ostree-lzma-common.h" + +#include +#include +#include + +enum { + PROP_0, + PROP_PARAMS +}; + +/** + * SECTION:ostree-lzma-compressor + * @title: LZMA compressor + * + * An implementation of #GConverter that compresses data using + * LZMA. + */ + +static void _ostree_lzma_compressor_iface_init (GConverterIface *iface); + +/** + * OstreeLzmaCompressor: + * + * Zlib decompression + */ +struct _OstreeLzmaCompressor +{ + GObject parent_instance; + + GVariant *params; + lzma_stream lstream; + gboolean initialized; +}; + +G_DEFINE_TYPE_WITH_CODE (OstreeLzmaCompressor, _ostree_lzma_compressor, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, + _ostree_lzma_compressor_iface_init)) + +static void +_ostree_lzma_compressor_finalize (GObject *object) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (object); + + lzma_end (&self->lstream); + g_clear_pointer (&self->params, (GDestroyNotify)g_variant_unref); + + G_OBJECT_CLASS (_ostree_lzma_compressor_parent_class)->finalize (object); +} + +static void +_ostree_lzma_compressor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (object); + + switch (prop_id) + { + case PROP_PARAMS: + self->params = g_value_get_variant (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + +} + +static void +_ostree_lzma_compressor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (object); + + switch (prop_id) + { + case PROP_PARAMS: + g_value_set_variant (value, self->params); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +_ostree_lzma_compressor_init (OstreeLzmaCompressor *self) +{ + lzma_stream tmp = LZMA_STREAM_INIT; + self->lstream = tmp; +} + +static void +_ostree_lzma_compressor_class_init (OstreeLzmaCompressorClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = _ostree_lzma_compressor_finalize; + gobject_class->get_property = _ostree_lzma_compressor_get_property; + gobject_class->set_property = _ostree_lzma_compressor_set_property; + + g_object_class_install_property (gobject_class, + PROP_PARAMS, + g_param_spec_variant ("params", "", "", + G_VARIANT_TYPE ("a{sv}"), + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +OstreeLzmaCompressor * +_ostree_lzma_compressor_new (GVariant *params) +{ + return g_object_new (OSTREE_TYPE_LZMA_COMPRESSOR, + "params", params, + NULL); +} + +static void +_ostree_lzma_compressor_reset (GConverter *converter) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (converter); + + if (self->initialized) + { + lzma_stream tmp = LZMA_STREAM_INIT; + lzma_end (&self->lstream); + self->lstream = tmp; + self->initialized = FALSE; + } +} + +static GConverterResult +_ostree_lzma_compressor_convert (GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error) +{ + OstreeLzmaCompressor *self = OSTREE_LZMA_COMPRESSOR (converter); + int res; + lzma_action action; + + if (inbuf_size != 0 && outbuf_size == 0) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE, + "Output buffer too small"); + return G_CONVERTER_ERROR; + } + + if (!self->initialized) + { + res = lzma_easy_encoder (&self->lstream, 8, LZMA_CHECK_CRC64); + if (res != LZMA_OK) + goto out; + self->initialized = TRUE; + } + + self->lstream.next_in = (void *)inbuf; + self->lstream.avail_in = inbuf_size; + + self->lstream.next_out = outbuf; + self->lstream.avail_out = outbuf_size; + + action = LZMA_RUN; + if (flags & G_CONVERTER_INPUT_AT_END) + action = LZMA_FINISH; + else if (flags & G_CONVERTER_FLUSH) + action = LZMA_SYNC_FLUSH; + + res = lzma_code (&self->lstream, action); + if (res != LZMA_OK && res != LZMA_STREAM_END) + goto out; + + *bytes_read = inbuf_size - self->lstream.avail_in; + *bytes_written = outbuf_size - self->lstream.avail_out; + + out: + return _ostree_lzma_return (res, error); +} + +static void +_ostree_lzma_compressor_iface_init (GConverterIface *iface) +{ + iface->convert = _ostree_lzma_compressor_convert; + iface->reset = _ostree_lzma_compressor_reset; +} diff --git a/src/libostree/ostree-lzma-compressor.h b/src/libostree/ostree-lzma-compressor.h new file mode 100644 index 0000000..5f3da18 --- /dev/null +++ b/src/libostree/ostree-lzma-compressor.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_LZMA_COMPRESSOR (_ostree_lzma_compressor_get_type ()) +#define OSTREE_LZMA_COMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_LZMA_COMPRESSOR, OstreeLzmaCompressor)) +#define OSTREE_LZMA_COMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_LZMA_COMPRESSOR, OstreeLzmaCompressorClass)) +#define OSTREE_IS_LZMA_COMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_LZMA_COMPRESSOR)) +#define OSTREE_IS_LZMA_COMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_LZMA_COMPRESSOR)) +#define OSTREE_LZMA_COMPRESSOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_LZMA_COMPRESSOR, OstreeLzmaCompressorClass)) + +typedef struct _OstreeLzmaCompressorClass OstreeLzmaCompressorClass; +typedef struct _OstreeLzmaCompressor OstreeLzmaCompressor; + +struct _OstreeLzmaCompressorClass +{ + GObjectClass parent_class; +}; + +GType _ostree_lzma_compressor_get_type (void) G_GNUC_CONST; + +OstreeLzmaCompressor *_ostree_lzma_compressor_new (GVariant *params); + +G_END_DECLS diff --git a/src/libostree/ostree-lzma-decompressor.c b/src/libostree/ostree-lzma-decompressor.c new file mode 100644 index 0000000..029159e --- /dev/null +++ b/src/libostree/ostree-lzma-decompressor.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "ostree-lzma-decompressor.h" +#include "ostree-lzma-common.h" + +#include +#include +#include + +enum { + PROP_0, +}; + +/** + * SECTION:ostree-lzma-decompressor + * @title: LZMA decompressor + * + * An implementation of #GConverter that decompresses data using + * LZMA. + */ + +static void _ostree_lzma_decompressor_iface_init (GConverterIface *iface); + +struct _OstreeLzmaDecompressor +{ + GObject parent_instance; + + lzma_stream lstream; + gboolean initialized; +}; + +G_DEFINE_TYPE_WITH_CODE (OstreeLzmaDecompressor, _ostree_lzma_decompressor, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, + _ostree_lzma_decompressor_iface_init)) + +static void +_ostree_lzma_decompressor_finalize (GObject *object) +{ + OstreeLzmaDecompressor *self; + + self = OSTREE_LZMA_DECOMPRESSOR (object); + lzma_end (&self->lstream); + + G_OBJECT_CLASS (_ostree_lzma_decompressor_parent_class)->finalize (object); +} + +static void +_ostree_lzma_decompressor_init (OstreeLzmaDecompressor *self) +{ + lzma_stream tmp = LZMA_STREAM_INIT; + self->lstream = tmp; +} + +static void +_ostree_lzma_decompressor_class_init (OstreeLzmaDecompressorClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = _ostree_lzma_decompressor_finalize; +} + +OstreeLzmaDecompressor * +_ostree_lzma_decompressor_new (void) +{ + return g_object_new (OSTREE_TYPE_LZMA_DECOMPRESSOR, NULL); +} + +static void +_ostree_lzma_decompressor_reset (GConverter *converter) +{ + OstreeLzmaDecompressor *self = OSTREE_LZMA_DECOMPRESSOR (converter); + + if (self->initialized) + { + lzma_stream tmp = LZMA_STREAM_INIT; + lzma_end (&self->lstream); + self->lstream = tmp; + self->initialized = FALSE; + } +} + +static GConverterResult +_ostree_lzma_decompressor_convert (GConverter *converter, + const void *inbuf, + gsize inbuf_size, + void *outbuf, + gsize outbuf_size, + GConverterFlags flags, + gsize *bytes_read, + gsize *bytes_written, + GError **error) +{ + OstreeLzmaDecompressor *self = OSTREE_LZMA_DECOMPRESSOR (converter); + int res; + + if (inbuf_size != 0 && outbuf_size == 0) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE, + "Output buffer too small"); + return G_CONVERTER_ERROR; + } + + if (!self->initialized) + { + res = lzma_stream_decoder (&self->lstream, G_MAXUINT64, 0); + if (res != LZMA_OK) + goto out; + self->initialized = TRUE; + } + + self->lstream.next_in = (void *)inbuf; + self->lstream.avail_in = inbuf_size; + + self->lstream.next_out = outbuf; + self->lstream.avail_out = outbuf_size; + + res = lzma_code (&self->lstream, LZMA_RUN); + if (res != LZMA_OK && res != LZMA_STREAM_END) + goto out; + + *bytes_read = inbuf_size - self->lstream.avail_in; + *bytes_written = outbuf_size - self->lstream.avail_out; + + out: + return _ostree_lzma_return (res, error); +} + +static void +_ostree_lzma_decompressor_iface_init (GConverterIface *iface) +{ + iface->convert = _ostree_lzma_decompressor_convert; + iface->reset = _ostree_lzma_decompressor_reset; +} diff --git a/src/libostree/ostree-lzma-decompressor.h b/src/libostree/ostree-lzma-decompressor.h new file mode 100644 index 0000000..231f214 --- /dev/null +++ b/src/libostree/ostree-lzma-decompressor.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_LZMA_DECOMPRESSOR (_ostree_lzma_decompressor_get_type ()) +#define OSTREE_LZMA_DECOMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_LZMA_DECOMPRESSOR, OstreeLzmaDecompressor)) +#define OSTREE_LZMA_DECOMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_LZMA_DECOMPRESSOR, OstreeLzmaDecompressorClass)) +#define OSTREE_IS_LZMA_DECOMPRESSOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_LZMA_DECOMPRESSOR)) +#define OSTREE_IS_LZMA_DECOMPRESSOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_LZMA_DECOMPRESSOR)) +#define OSTREE_LZMA_DECOMPRESSOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_LZMA_DECOMPRESSOR, OstreeLzmaDecompressorClass)) + +typedef struct _OstreeLzmaDecompressorClass OstreeLzmaDecompressorClass; +typedef struct _OstreeLzmaDecompressor OstreeLzmaDecompressor; + +struct _OstreeLzmaDecompressorClass +{ + GObjectClass parent_class; +}; + +GLIB_AVAILABLE_IN_ALL +GType _ostree_lzma_decompressor_get_type (void) G_GNUC_CONST; + +GLIB_AVAILABLE_IN_ALL +OstreeLzmaDecompressor *_ostree_lzma_decompressor_new (void); + +G_END_DECLS diff --git a/src/libostree/ostree-metalink.c b/src/libostree/ostree-metalink.c new file mode 100644 index 0000000..cb8a50e --- /dev/null +++ b/src/libostree/ostree-metalink.c @@ -0,0 +1,644 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-metalink.h" +#include "ostree-fetcher-util.h" +#include + +#include "otutil.h" + +typedef enum { + OSTREE_METALINK_STATE_INITIAL, + OSTREE_METALINK_STATE_METALINK, + OSTREE_METALINK_STATE_FILES, + OSTREE_METALINK_STATE_FILE, + OSTREE_METALINK_STATE_SIZE, + OSTREE_METALINK_STATE_VERIFICATION, + OSTREE_METALINK_STATE_HASH, + OSTREE_METALINK_STATE_RESOURCES, + OSTREE_METALINK_STATE_URL, + + OSTREE_METALINK_STATE_PASSTHROUGH /* Ignoring unknown elements */ +} OstreeMetalinkState; + +struct OstreeMetalink +{ + GObject parent_instance; + + OstreeFetcherURI *uri; + + OstreeFetcher *fetcher; + char *requested_file; + guint64 max_size; + guint n_network_retries; +}; + +G_DEFINE_TYPE (OstreeMetalink, _ostree_metalink, G_TYPE_OBJECT) + +typedef struct +{ + OstreeMetalink *metalink; + + GCancellable *cancellable; + GMarkupParseContext *parser; + + guint passthrough_depth; + OstreeMetalinkState passthrough_previous; + + guint found_a_file_element : 1; + guint found_our_file_element : 1; + guint verification_known : 1; + + GChecksumType in_verification_type; + + guint64 size; + char *verification_sha256; + char *verification_sha512; + + GBytes *result; + + char *last_metalink_error; + guint current_url_index; + GPtrArray *urls; + + OstreeMetalinkState state; +} OstreeMetalinkRequest; + +static void +state_transition (OstreeMetalinkRequest *self, + OstreeMetalinkState new_state) +{ + g_assert (self->state != new_state); + + if (new_state == OSTREE_METALINK_STATE_PASSTHROUGH) + self->passthrough_previous = self->state; + + self->state = new_state; +} + +static void +unknown_element (OstreeMetalinkRequest *self, + const char *element_name, + GError **error) +{ + state_transition (self, OSTREE_METALINK_STATE_PASSTHROUGH); + g_assert (self->passthrough_depth == 0); +} + +static void +metalink_parser_start (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + OstreeMetalinkRequest *self = user_data; + + switch (self->state) + { + case OSTREE_METALINK_STATE_INITIAL: + if (strcmp (element_name, "metalink") == 0) + state_transition (self, OSTREE_METALINK_STATE_METALINK); + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_METALINK: + if (strcmp (element_name, "files") == 0) + state_transition (self, OSTREE_METALINK_STATE_FILES); + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_FILES: + /* If we've already processed a element we're OK with, just + * ignore the others. + */ + if (self->urls->len > 0) + { + state_transition (self, OSTREE_METALINK_STATE_PASSTHROUGH); + } + else if (strcmp (element_name, "file") == 0) + { + const char *file_name; + + if (!g_markup_collect_attributes (element_name, + attribute_names, + attribute_values, + error, + G_MARKUP_COLLECT_STRING, + "name", + &file_name, + G_MARKUP_COLLECT_INVALID)) + goto out; + + self->found_a_file_element = TRUE; + + if (strcmp (file_name, self->metalink->requested_file) != 0) + { + state_transition (self, OSTREE_METALINK_STATE_PASSTHROUGH); + g_assert (self->passthrough_depth == 0); + } + else + { + self->found_our_file_element = TRUE; + state_transition (self, OSTREE_METALINK_STATE_FILE); + } + } + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_FILE: + if (strcmp (element_name, "size") == 0) + state_transition (self, OSTREE_METALINK_STATE_SIZE); + else if (strcmp (element_name, "verification") == 0) + state_transition (self, OSTREE_METALINK_STATE_VERIFICATION); + else if (strcmp (element_name, "resources") == 0) + state_transition (self, OSTREE_METALINK_STATE_RESOURCES); + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_SIZE: + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_VERIFICATION: + if (strcmp (element_name, "hash") == 0) + { + char *verification_type_str = NULL; + + state_transition (self, OSTREE_METALINK_STATE_HASH); + if (!g_markup_collect_attributes (element_name, + attribute_names, + attribute_values, + error, + G_MARKUP_COLLECT_STRING, + "type", + &verification_type_str, + G_MARKUP_COLLECT_INVALID)) + goto out; + + /* Only accept sha256/sha512 */ + self->verification_known = TRUE; + if (strcmp (verification_type_str, "sha256") == 0) + self->in_verification_type = G_CHECKSUM_SHA256; + else if (strcmp (verification_type_str, "sha512") == 0) + self->in_verification_type = G_CHECKSUM_SHA512; + else + self->verification_known = FALSE; + } + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_HASH: + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_RESOURCES: + if (self->size == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No element found or it is zero"); + goto out; + } + if (!self->verification_known) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No element with known found"); + goto out; + } + + if (strcmp (element_name, "url") == 0) + { + const char *protocol; + + if (!g_markup_collect_attributes (element_name, + attribute_names, + attribute_values, + error, + G_MARKUP_COLLECT_STRING, + "protocol", + &protocol, + G_MARKUP_COLLECT_STRING, + "type", + NULL, + G_MARKUP_COLLECT_STRING, + "location", + NULL, + G_MARKUP_COLLECT_STRING, + "preference", + NULL, + G_MARKUP_COLLECT_INVALID)) + goto out; + + /* Ignore non-HTTP resources */ + if (!(strcmp (protocol, "http") == 0 || strcmp (protocol, "https") == 0)) + state_transition (self, OSTREE_METALINK_STATE_PASSTHROUGH); + else + state_transition (self, OSTREE_METALINK_STATE_URL); + } + else + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_URL: + unknown_element (self, element_name, error); + break; + case OSTREE_METALINK_STATE_PASSTHROUGH: + self->passthrough_depth++; + break; + } + + out: + return; +} + +static void +metalink_parser_end (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + OstreeMetalinkRequest *self = user_data; + + switch (self->state) + { + case OSTREE_METALINK_STATE_INITIAL: + break; + case OSTREE_METALINK_STATE_METALINK: + state_transition (self, OSTREE_METALINK_STATE_INITIAL); + break; + case OSTREE_METALINK_STATE_FILES: + state_transition (self, OSTREE_METALINK_STATE_METALINK); + break; + case OSTREE_METALINK_STATE_FILE: + state_transition (self, OSTREE_METALINK_STATE_FILES); + break; + case OSTREE_METALINK_STATE_SIZE: + case OSTREE_METALINK_STATE_VERIFICATION: + case OSTREE_METALINK_STATE_RESOURCES: + state_transition (self, OSTREE_METALINK_STATE_FILE); + break; + case OSTREE_METALINK_STATE_HASH: + state_transition (self, OSTREE_METALINK_STATE_VERIFICATION); + break; + case OSTREE_METALINK_STATE_URL: + state_transition (self, OSTREE_METALINK_STATE_RESOURCES); + break; + case OSTREE_METALINK_STATE_PASSTHROUGH: + if (self->passthrough_depth > 0) + self->passthrough_depth--; + else + state_transition (self, self->passthrough_previous); + break; + } +} + +static void +metalink_parser_text (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + OstreeMetalinkRequest *self = user_data; + + switch (self->state) + { + case OSTREE_METALINK_STATE_INITIAL: + break; + case OSTREE_METALINK_STATE_METALINK: + break; + case OSTREE_METALINK_STATE_FILES: + break; + case OSTREE_METALINK_STATE_FILE: + break; + case OSTREE_METALINK_STATE_SIZE: + { + g_autofree char *duped = g_strndup (text, text_len); + self->size = g_ascii_strtoull (duped, NULL, 10); + } + break; + case OSTREE_METALINK_STATE_VERIFICATION: + break; + case OSTREE_METALINK_STATE_HASH: + if (self->verification_known) + { + switch (self->in_verification_type) + { + case G_CHECKSUM_SHA256: + g_free (self->verification_sha256); + self->verification_sha256 = g_strndup (text, text_len); + break; + case G_CHECKSUM_SHA512: + g_free (self->verification_sha512); + self->verification_sha512 = g_strndup (text, text_len); + break; + default: + g_assert_not_reached (); + } + } + break; + case OSTREE_METALINK_STATE_RESOURCES: + break; + case OSTREE_METALINK_STATE_URL: + { + g_autofree char *uri_text = g_strndup (text, text_len); + OstreeFetcherURI *uri = _ostree_fetcher_uri_parse (uri_text, NULL); + if (uri != NULL) + g_ptr_array_add (self->urls, uri); + } + break; + case OSTREE_METALINK_STATE_PASSTHROUGH: + break; + } + +} + +static void +_ostree_metalink_finalize (GObject *object) +{ + OstreeMetalink *self; + + self = OSTREE_METALINK (object); + + g_object_unref (self->fetcher); + g_free (self->requested_file); + _ostree_fetcher_uri_free (self->uri); + + G_OBJECT_CLASS (_ostree_metalink_parent_class)->finalize (object); +} + +static void +_ostree_metalink_class_init (OstreeMetalinkClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = _ostree_metalink_finalize; +} + +static void +_ostree_metalink_init (OstreeMetalink *self) +{ +} + +OstreeMetalink * +_ostree_metalink_new (OstreeFetcher *fetcher, + const char *requested_file, + guint64 max_size, + OstreeFetcherURI *uri, + guint n_network_retries) +{ + OstreeMetalink *self = (OstreeMetalink*)g_object_new (OSTREE_TYPE_METALINK, NULL); + + self->fetcher = g_object_ref (fetcher); + self->requested_file = g_strdup (requested_file); + self->max_size = max_size; + self->uri = _ostree_fetcher_uri_clone (uri); + self->n_network_retries = n_network_retries; + + return self; +} + +static gboolean +valid_hex_checksum (const char *s, gsize expected_len) +{ + gsize len = strspn (s, "01234567890abcdef"); + + return len == expected_len && s[len] == '\0'; +} + +static gboolean +try_one_url (OstreeMetalinkRequest *self, + OstreeFetcherURI *uri, + GBytes **out_data, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GBytes) bytes = NULL; + gssize n_bytes; + + if (!_ostree_fetcher_request_uri_to_membuf (self->metalink->fetcher, + uri, 0, + self->metalink->n_network_retries, + &bytes, + self->metalink->max_size, + self->cancellable, + error)) + goto out; + + n_bytes = g_bytes_get_size (bytes); + if (n_bytes != self->size) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Expected size is %" G_GUINT64_FORMAT " bytes but content is %" G_GSSIZE_FORMAT " bytes", + self->size, n_bytes); + goto out; + } + + if (self->verification_sha512) + { + g_autofree char *actual = NULL; + + actual = g_compute_checksum_for_bytes (G_CHECKSUM_SHA512, bytes); + + if (strcmp (self->verification_sha512, actual) != 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Expected checksum is %s but actual is %s", + self->verification_sha512, actual); + goto out; + } + } + else if (self->verification_sha256) + { + g_autofree char *actual = NULL; + + actual = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, bytes); + + if (strcmp (self->verification_sha256, actual) != 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Expected checksum is %s but actual is %s", + self->verification_sha256, actual); + goto out; + } + } + + ret = TRUE; + if (out_data) + *out_data = g_steal_pointer (&bytes); + out: + return ret; +} + +static gboolean +try_metalink_targets (OstreeMetalinkRequest *self, + OstreeFetcherURI **out_target_uri, + GBytes **out_data, + GError **error) +{ + gboolean ret = FALSE; + OstreeFetcherURI *target_uri = NULL; + g_autoptr(GBytes) ret_data = NULL; + + if (!self->found_a_file_element) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No element found"); + goto out; + } + + if (!self->found_our_file_element) + { + /* XXX Use NOT_FOUND here so we can distinguish not finding the + * requested file from other errors. This is a bit of a hack + * through; metalinks should have their own error enum. */ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No found", self->metalink->requested_file); + goto out; + } + + if (!(self->verification_sha256 || self->verification_sha512)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No hash for sha256 or sha512 found"); + goto out; + } + + if (self->verification_sha256 && !valid_hex_checksum (self->verification_sha256, 64)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid hash digest for sha256"); + goto out; + } + + if (self->verification_sha512 && !valid_hex_checksum (self->verification_sha512, 128)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid hash digest for sha512"); + goto out; + } + + if (self->urls->len == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No elements found"); + goto out; + } + + for (self->current_url_index = 0; + self->current_url_index < self->urls->len; + self->current_url_index++) + { + GError *temp_error = NULL; + + target_uri = self->urls->pdata[self->current_url_index]; + + if (try_one_url (self, target_uri, &ret_data, &temp_error)) + break; + else + { + g_free (self->last_metalink_error); + self->last_metalink_error = g_strdup (temp_error->message); + g_clear_error (&temp_error); + } + } + + if (self->current_url_index >= self->urls->len) + { + g_assert (self->last_metalink_error != NULL); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Exhausted %u metalink targets, last error: %s", + self->urls->len, self->last_metalink_error); + goto out; + } + + ret = TRUE; + if (out_target_uri) + *out_target_uri = _ostree_fetcher_uri_clone (target_uri); + if (out_data) + *out_data = g_steal_pointer (&ret_data); + out: + return ret; +} + +static const GMarkupParser metalink_parser = { + metalink_parser_start, + metalink_parser_end, + metalink_parser_text, + NULL, + NULL +}; + +typedef struct +{ + OstreeFetcherURI **out_target_uri; + GBytes **out_data; + gboolean success; + GError **error; + GMainLoop *loop; +} FetchMetalinkSyncData; + +gboolean +_ostree_metalink_request_sync (OstreeMetalink *self, + OstreeFetcherURI **out_target_uri, + GBytes **out_data, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + OstreeMetalinkRequest request = { 0, }; + g_autoptr(GMainContext) mainctx = NULL; + g_autoptr(GBytes) contents = NULL; + gsize len; + const guint8 *data; + + mainctx = g_main_context_new (); + g_main_context_push_thread_default (mainctx); + + request.metalink = g_object_ref (self); + request.urls = g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free); + request.parser = g_markup_parse_context_new (&metalink_parser, G_MARKUP_PREFIX_ERROR_POSITION, &request, NULL); + + if (!_ostree_fetcher_request_uri_to_membuf (self->fetcher, self->uri, 0, + self->n_network_retries, + &contents, self->max_size, + cancellable, error)) + goto out; + + data = g_bytes_get_data (contents, &len); + if (!g_markup_parse_context_parse (request.parser, (const char*)data, len, error)) + goto out; + + if (!try_metalink_targets (&request, out_target_uri, out_data, error)) + goto out; + + ret = TRUE; + out: + if (mainctx) + g_main_context_pop_thread_default (mainctx); + g_clear_object (&request.metalink); + g_clear_pointer (&request.verification_sha256, g_free); + g_clear_pointer (&request.verification_sha512, g_free); + g_clear_pointer (&request.last_metalink_error, g_free); + g_clear_pointer (&request.urls, g_ptr_array_unref); + g_clear_pointer (&request.parser, g_markup_parse_context_free); + return ret; +} diff --git a/src/libostree/ostree-metalink.h b/src/libostree/ostree-metalink.h new file mode 100644 index 0000000..1a48945 --- /dev/null +++ b/src/libostree/ostree-metalink.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#ifndef __GI_SCANNER__ + +#include "ostree-fetcher.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_METALINK (_ostree_metalink_get_type ()) +#define OSTREE_METALINK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_METALINK, OstreeMetalink)) +#define OSTREE_METALINK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_METALINK, OstreeMetalinkClass)) +#define OSTREE_IS_METALINK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_METALINK)) +#define OSTREE_IS_METALINK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_METALINK)) +#define OSTREE_METALINK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_METALINK, OstreeMetalinkClass)) + +typedef struct OstreeMetalinkClass OstreeMetalinkClass; +typedef struct OstreeMetalink OstreeMetalink; + +struct OstreeMetalinkClass +{ + GObjectClass parent_class; +}; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeMetalink, g_object_unref) + +GType _ostree_metalink_get_type (void) G_GNUC_CONST; + +OstreeMetalink *_ostree_metalink_new (OstreeFetcher *fetcher, + const char *requested_file, + guint64 max_size, + OstreeFetcherURI *uri, + guint n_network_retries); + +gboolean _ostree_metalink_request_sync (OstreeMetalink *self, + OstreeFetcherURI **out_target_uri, + GBytes **out_data, + GCancellable *cancellable, + GError **error); +G_END_DECLS + +#endif diff --git a/src/libostree/ostree-mutable-tree.c b/src/libostree/ostree-mutable-tree.c new file mode 100644 index 0000000..8509d15 --- /dev/null +++ b/src/libostree/ostree-mutable-tree.c @@ -0,0 +1,683 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "otutil.h" +#include "ostree.h" + +#include "ostree-core-private.h" + +/** + * SECTION:ostree-mutable-tree + * @title: In-memory modifiable filesystem tree + * @short_description: Modifiable filesystem tree + * + * In order to commit content into an #OstreeRepo, it must first be + * imported into an #OstreeMutableTree. There are several high level + * APIs to create an initiable #OstreeMutableTree from a physical + * filesystem directory, but they may also be computed + * programmatically. + */ + +typedef enum { + MTREE_STATE_WHOLE, + + /* MTREE_STATE_LAZY allows us to not read files and subdirs from the objects + * on disk until they're actually needed - often they won't be needed at + * all. */ + MTREE_STATE_LAZY +} OstreeMutableTreeState; + +/** + * OstreeMutableTree: + * + * Private instance structure. + */ +struct OstreeMutableTree +{ + GObject parent_instance; + + /* The parent directory to this one. We don't hold a ref because this mtree + * is owned by the parent. We can be certain that any mtree only has one + * parent because external users can't set this, it's only set when we create + * a child from within this file (see insert_child_mtree). We ensure that the + * parent pointer is either valid or NULL because when the parent is destroyed + * it sets parent = NULL on all its children (see remove_child_mtree) */ + OstreeMutableTree *parent; + + OstreeMutableTreeState state; + + /* This is the checksum of the Dirtree object that corresponds to the current + * contents of this directory. contents_checksum can be NULL if the SHA was + * never calculated or contents of this mtree or any subdirectory has been + * modified. If a contents_checksum is NULL then all the parent's checksums + * will be NULL (see `invalidate_contents_checksum`). + * + * Note: This invariant is partially maintained externally - we + * rely on the callers of `ostree_mutable_tree_set_contents_checksum` to have + * first ensured that the mtree contents really does correspond to this + * checksum */ + char *contents_checksum; + + /* This is the checksum of the DirMeta object that holds the uid, gid, mode + * and xattrs of this directory. This can be NULL. */ + char *metadata_checksum; + + /* ======== Valid for state LAZY: =========== */ + + /* The repo so we can look up the checksums. */ + OstreeRepo *repo; + + GError *cached_error; + + /* ======== Valid for state WHOLE: ========== */ + + /* const char* filename -> const char* checksum. */ + GHashTable *files; + + /* const char* filename -> OstreeMutableTree* subtree */ + GHashTable *subdirs; +}; + +G_DEFINE_TYPE (OstreeMutableTree, ostree_mutable_tree, G_TYPE_OBJECT) + +static void +ostree_mutable_tree_finalize (GObject *object) +{ + OstreeMutableTree *self; + + self = OSTREE_MUTABLE_TREE (object); + + g_free (self->contents_checksum); + g_free (self->metadata_checksum); + + g_clear_pointer (&self->cached_error, g_error_free); + g_hash_table_destroy (self->files); + g_hash_table_destroy (self->subdirs); + + g_clear_object (&self->repo); + + G_OBJECT_CLASS (ostree_mutable_tree_parent_class)->finalize (object); +} + +static void +ostree_mutable_tree_class_init (OstreeMutableTreeClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = ostree_mutable_tree_finalize; +} + +/* This must not be made public or we can't maintain the invariant that any + * OstreeMutableTree has only one parent. + * + * Ownership of @child is transferred from the caller to @self */ +static void +insert_child_mtree (OstreeMutableTree *self, const gchar* name, + OstreeMutableTree *child) +{ + g_assert_null (child->parent); + g_hash_table_insert (self->subdirs, g_strdup (name), child); + child->parent = self; +} + +static void +remove_child_mtree (gpointer data) +{ + /* Each mtree has shared ownership of its children and each child has a + * non-owning reference back to parent. If the parent goes out of scope the + * children may still be alive because they're reference counted. This + * removes the reference to the parent before it goes stale. */ + OstreeMutableTree *child = (OstreeMutableTree*) data; + child->parent = NULL; + g_object_unref (child); +} + +static void +ostree_mutable_tree_init (OstreeMutableTree *self) +{ + self->files = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + self->subdirs = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, remove_child_mtree); + self->state = MTREE_STATE_WHOLE; +} + +static void +invalidate_contents_checksum (OstreeMutableTree *self) +{ + while (self) { + if (!self->contents_checksum) + break; + + g_clear_pointer (&self->contents_checksum, g_free); + self = self->parent; + } +} + +/* Go from state LAZY to state WHOLE by reading the tree from disk */ +static gboolean +_ostree_mutable_tree_make_whole (OstreeMutableTree *self, + GCancellable *cancellable, + GError **error) +{ + if (self->state == MTREE_STATE_WHOLE) + return TRUE; + + g_assert_cmpuint (self->state, ==, MTREE_STATE_LAZY); + g_assert_nonnull (self->repo); + g_assert_nonnull (self->contents_checksum); + g_assert_nonnull (self->metadata_checksum); + g_assert_cmpuint (g_hash_table_size (self->files), ==, 0); + g_assert_cmpuint (g_hash_table_size (self->subdirs), ==, 0); + + g_autoptr(GVariant) dirtree = NULL; + if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_DIR_TREE, + self->contents_checksum, &dirtree, error)) + return FALSE; + + { + g_autoptr(GVariant) dir_file_contents = g_variant_get_child_value (dirtree, 0); + GVariantIter viter; + g_variant_iter_init (&viter, dir_file_contents); + const char *fname; + GVariant *contents_csum_v = NULL; + while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, &contents_csum_v)) + { + char tmp_checksum[OSTREE_SHA256_STRING_LEN + 1]; + _ostree_checksum_inplace_from_bytes_v (contents_csum_v, tmp_checksum); + g_hash_table_insert (self->files, g_strdup (fname), + g_strdup (tmp_checksum)); + } + } + + /* Process subdirectories */ + { + g_autoptr(GVariant) dir_subdirs = g_variant_get_child_value (dirtree, 1); + const char *dname; + GVariant *subdirtree_csum_v = NULL; + GVariant *subdirmeta_csum_v = NULL; + GVariantIter viter; + g_variant_iter_init (&viter, dir_subdirs); + while (g_variant_iter_loop (&viter, "(&s@ay@ay)", &dname, + &subdirtree_csum_v, &subdirmeta_csum_v)) + { + char subdirtree_checksum[OSTREE_SHA256_STRING_LEN+1]; + _ostree_checksum_inplace_from_bytes_v (subdirtree_csum_v, subdirtree_checksum); + char subdirmeta_checksum[OSTREE_SHA256_STRING_LEN+1]; + _ostree_checksum_inplace_from_bytes_v (subdirmeta_csum_v, subdirmeta_checksum); + insert_child_mtree (self, dname, ostree_mutable_tree_new_from_checksum ( + self->repo, subdirtree_checksum, subdirmeta_checksum)); + } + } + + g_clear_object (&self->repo); + self->state = MTREE_STATE_WHOLE; + return TRUE; +} + +/* _ostree_mutable_tree_make_whole can fail if state == MTREE_STATE_LAZY, but + * we have getters that preceed the existence of MTREE_STATE_LAZY which can't + * return errors. So instead this function will fail and print a warning. */ +static gboolean +_assert_ostree_mutable_tree_make_whole (OstreeMutableTree *self) +{ + if (self->cached_error) + return FALSE; + return _ostree_mutable_tree_make_whole (self, NULL, &self->cached_error); +} + +void +ostree_mutable_tree_set_metadata_checksum (OstreeMutableTree *self, + const char *checksum) +{ + if (g_strcmp0 (checksum, self->metadata_checksum) == 0) + return; + + invalidate_contents_checksum (self->parent); + g_free (self->metadata_checksum); + self->metadata_checksum = g_strdup (checksum); +} + +const char * +ostree_mutable_tree_get_metadata_checksum (OstreeMutableTree *self) +{ + return self->metadata_checksum; +} + +void +ostree_mutable_tree_set_contents_checksum (OstreeMutableTree *self, + const char *checksum) +{ + if (g_strcmp0 (checksum, self->contents_checksum) == 0) + return; + + if (checksum && self->contents_checksum) + g_warning ("Setting a contents checksum on an OstreeMutableTree that " + "already has a checksum set. Old checksum %s, new checksum %s", + self->contents_checksum, checksum); + + _assert_ostree_mutable_tree_make_whole (self); + + g_free (self->contents_checksum); + self->contents_checksum = g_strdup (checksum); +} + +const char * +ostree_mutable_tree_get_contents_checksum (OstreeMutableTree *self) +{ + return self->contents_checksum; +} + +static gboolean +set_error_noent (GError **error, const char *path) +{ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No such file or directory: %s", + path); + return FALSE; +} + +gboolean +ostree_mutable_tree_replace_file (OstreeMutableTree *self, + const char *name, + const char *checksum, + GError **error) +{ + g_return_val_if_fail (name != NULL, FALSE); + + if (!ot_util_filename_validate (name, error)) + return FALSE; + + if (!_ostree_mutable_tree_make_whole (self, NULL, error)) + return FALSE; + + if (g_hash_table_lookup (self->subdirs, name)) + return glnx_throw (error, "Can't replace directory with file: %s", name); + + invalidate_contents_checksum (self); + g_hash_table_replace (self->files, + g_strdup (name), + g_strdup (checksum)); + return TRUE; +} + +/** + * ostree_mutable_tree_remove: + * @self: Tree + * @name: Name of file or subdirectory to remove + * @allow_noent: If @FALSE, an error will be thrown if @name does not exist in the tree + * @error: a #GError + * + * Remove the file or subdirectory named @name from the mutable tree @self. + * + * Since: 2018.9 + */ +gboolean +ostree_mutable_tree_remove (OstreeMutableTree *self, + const char *name, + gboolean allow_noent, + GError **error) +{ + g_return_val_if_fail (name != NULL, FALSE); + + if (!ot_util_filename_validate (name, error)) + return FALSE; + + if (!_ostree_mutable_tree_make_whole (self, NULL, error)) + return FALSE; + + if (!g_hash_table_remove (self->files, name) && + !g_hash_table_remove (self->subdirs, name)) + { + if (allow_noent) + return TRUE; /* NB: early return */ + return set_error_noent (error, name); + } + + invalidate_contents_checksum (self); + return TRUE; +} + +/** + * ostree_mutable_tree_ensure_dir: + * @self: Tree + * @name: Name of subdirectory of self to retrieve/creates + * @out_subdir: (out) (transfer full): the subdirectory + * @error: a #GError + * + * Returns the subdirectory of self with filename @name, creating an empty one + * it if it doesn't exist. + */ +gboolean +ostree_mutable_tree_ensure_dir (OstreeMutableTree *self, + const char *name, + OstreeMutableTree **out_subdir, + GError **error) +{ + g_return_val_if_fail (name != NULL, FALSE); + + if (!ot_util_filename_validate (name, error)) + return FALSE; + + if (!_ostree_mutable_tree_make_whole (self, NULL, error)) + return FALSE; + + if (g_hash_table_lookup (self->files, name)) + return glnx_throw (error, "Can't replace file with directory: %s", name); + + g_autoptr(OstreeMutableTree) ret_dir = + ot_gobject_refz (g_hash_table_lookup (self->subdirs, name)); + if (!ret_dir) + { + ret_dir = ostree_mutable_tree_new (); + invalidate_contents_checksum (self); + insert_child_mtree (self, name, g_object_ref (ret_dir)); + } + + if (out_subdir) + *out_subdir = g_steal_pointer (&ret_dir); + return TRUE; +} + +/** + * ostree_mutable_tree_lookup: + * @self: Tree + * @name: name + * @out_file_checksum: (out) (transfer full): checksum + * @out_subdir: (out) (transfer full): subdirectory + * @error: a #GError + */ +gboolean +ostree_mutable_tree_lookup (OstreeMutableTree *self, + const char *name, + char **out_file_checksum, + OstreeMutableTree **out_subdir, + GError **error) +{ + if (!_ostree_mutable_tree_make_whole (self, NULL, error)) + return FALSE; + + g_autofree char *ret_file_checksum = NULL; + g_autoptr(OstreeMutableTree) ret_subdir = + ot_gobject_refz (g_hash_table_lookup (self->subdirs, name)); + if (!ret_subdir) + { + ret_file_checksum = g_strdup (g_hash_table_lookup (self->files, name)); + if (!ret_file_checksum) + return set_error_noent (error, name); + } + + if (out_file_checksum) + *out_file_checksum = g_steal_pointer (&ret_file_checksum); + if (out_subdir) + *out_subdir = g_steal_pointer (&ret_subdir); + return TRUE; +} + +/** + * ostree_mutable_tree_ensure_parent_dirs: + * @self: Tree + * @split_path: (element-type utf8): File path components + * @metadata_checksum: SHA256 checksum for metadata + * @out_parent: (out) (transfer full): The parent tree + * @error: a #GError + * + * Create all parent trees necessary for the given @split_path to + * exist. + */ +gboolean +ostree_mutable_tree_ensure_parent_dirs (OstreeMutableTree *self, + GPtrArray *split_path, + const char *metadata_checksum, + OstreeMutableTree **out_parent, + GError **error) +{ + g_assert (metadata_checksum != NULL); + + if (!_ostree_mutable_tree_make_whole (self, NULL, error)) + return FALSE; + + if (!self->metadata_checksum) + ostree_mutable_tree_set_metadata_checksum (self, metadata_checksum); + + OstreeMutableTree *subdir = self; /* nofree */ + for (guint i = 0; i+1 < split_path->len; i++) + { + OstreeMutableTree *next; + const char *name = split_path->pdata[i]; + + if (g_hash_table_lookup (subdir->files, name)) + return glnx_throw (error, "Can't replace file with directory: %s", name); + + next = g_hash_table_lookup (subdir->subdirs, name); + if (!next) + { + invalidate_contents_checksum (subdir); + next = ostree_mutable_tree_new (); + ostree_mutable_tree_set_metadata_checksum (next, metadata_checksum); + insert_child_mtree (subdir, g_strdup (name), next); + } + + subdir = next; + } + + if (out_parent) + *out_parent = g_object_ref (subdir); + return TRUE; +} + +const char empty_tree_csum[] = "6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d"; + +/** + * ostree_mutable_tree_fill_empty_from_dirtree: + * + * Merges @self with the tree given by @contents_checksum and + * @metadata_checksum, but only if it's possible without writing new objects to + * the @repo. We can do this if either @self is empty, the tree given by + * @contents_checksum is empty or if both trees already have the same + * @contents_checksum. + * + * Returns: @TRUE if merge was successful, @FALSE if it was not possible. + * + * This function enables optimisations when composing trees. The provided + * checksums are not loaded or checked when this function is called. Instead + * the contents will be loaded only when needed. + * + * Since: 2018.7 + */ +gboolean +ostree_mutable_tree_fill_empty_from_dirtree (OstreeMutableTree *self, + OstreeRepo *repo, + const char *contents_checksum, + const char *metadata_checksum) +{ + g_return_val_if_fail (repo, FALSE); + g_return_val_if_fail (contents_checksum, FALSE); + g_return_val_if_fail (metadata_checksum, FALSE); + + switch (self->state) + { + case MTREE_STATE_LAZY: + { + if (g_strcmp0 (contents_checksum, self->contents_checksum) == 0 || + g_strcmp0 (empty_tree_csum, self->contents_checksum) == 0) + break; + + if (g_strcmp0 (empty_tree_csum, contents_checksum) == 0) + { + /* Adding an empty tree to a full one - stick with the old contents */ + contents_checksum = self->contents_checksum; + break; + } + else + return FALSE; + } + case MTREE_STATE_WHOLE: + if (g_hash_table_size (self->files) == 0 && + g_hash_table_size (self->subdirs) == 0) + break; + /* We're not empty - can't convert to a LAZY tree */ + return FALSE; + default: + g_assert_not_reached (); + } + + self->state = MTREE_STATE_LAZY; + g_set_object (&self->repo, repo); + ostree_mutable_tree_set_metadata_checksum (self, metadata_checksum); + if (g_strcmp0 (self->contents_checksum, contents_checksum) != 0) + { + invalidate_contents_checksum (self); + self->contents_checksum = g_strdup (contents_checksum); + } + return TRUE; +} + +/** + * ostree_mutable_tree_walk: + * @self: Tree + * @split_path: (element-type utf8): Split pathname + * @start: Descend from this number of elements in @split_path + * @out_subdir: (out) (transfer full): Target parent + * @error: Error + * + * Traverse @start number of elements starting from @split_path; the + * child will be returned in @out_subdir. + */ +gboolean +ostree_mutable_tree_walk (OstreeMutableTree *self, + GPtrArray *split_path, + guint start, + OstreeMutableTree **out_subdir, + GError **error) +{ + g_return_val_if_fail (start < split_path->len, FALSE); + + if (start == split_path->len - 1) + { + *out_subdir = g_object_ref (self); + return TRUE; + } + else + { + OstreeMutableTree *subdir; + if (!_ostree_mutable_tree_make_whole (self, NULL, error)) + return FALSE; + + subdir = g_hash_table_lookup (self->subdirs, split_path->pdata[start]); + if (!subdir) + return set_error_noent (error, (char*)split_path->pdata[start]); + + return ostree_mutable_tree_walk (subdir, split_path, start + 1, out_subdir, error); + } +} + +/** + * ostree_mutable_tree_get_subdirs: + * @self: + * + * Returns: (transfer none) (element-type utf8 OstreeMutableTree): All children directories + */ +GHashTable * +ostree_mutable_tree_get_subdirs (OstreeMutableTree *self) +{ + _assert_ostree_mutable_tree_make_whole (self); + return self->subdirs; +} + +/** + * ostree_mutable_tree_get_files: + * @self: + * + * Returns: (transfer none) (element-type utf8 utf8): All children files (the value is a checksum) + */ +GHashTable * +ostree_mutable_tree_get_files (OstreeMutableTree *self) +{ + _assert_ostree_mutable_tree_make_whole (self); + return self->files; +} + +/** + * ostree_mutable_tree_check_error: + * @self: Tree + * + * In some cases, a tree may be in a "lazy" state that loads + * data in the background; if an error occurred during a non-throwing + * API call, it will have been cached. This function checks for a + * cached error. The tree remains in error state. + * + * Since: 2018.7 + * Returns: `TRUE` on success + */ +gboolean +ostree_mutable_tree_check_error (OstreeMutableTree *self, + GError **error) +{ + if (self->cached_error) + { + if (error) + *error = g_error_copy (self->cached_error); + return FALSE; + } + return TRUE; +} + +/** + * ostree_mutable_tree_new: + * + * Returns: (transfer full): A new tree + */ +OstreeMutableTree * +ostree_mutable_tree_new (void) +{ + return (OstreeMutableTree*)g_object_new (OSTREE_TYPE_MUTABLE_TREE, NULL); +} + +/** + * ostree_mutable_tree_new_from_checksum: + * @repo: The repo which contains the objects refered by the checksums. + * @contents_checksum: dirtree checksum + * @metadata_checksum: dirmeta checksum + * + * Creates a new OstreeMutableTree with the contents taken from the given repo + * and checksums. The data will be loaded from the repo lazily as needed. + * + * Returns: (transfer full): A new tree + * + * Since: 2018.7 + */ +OstreeMutableTree * +ostree_mutable_tree_new_from_checksum (OstreeRepo *repo, + const char *contents_checksum, + const char *metadata_checksum) +{ + OstreeMutableTree* out = (OstreeMutableTree*)g_object_new (OSTREE_TYPE_MUTABLE_TREE, NULL); + out->state = MTREE_STATE_LAZY; + out->repo = g_object_ref (repo); + out->contents_checksum = g_strdup (contents_checksum); + out->metadata_checksum = g_strdup (metadata_checksum); + return out; +} diff --git a/src/libostree/ostree-mutable-tree.h b/src/libostree/ostree-mutable-tree.h new file mode 100644 index 0000000..753f96e --- /dev/null +++ b/src/libostree/ostree-mutable-tree.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_MUTABLE_TREE (ostree_mutable_tree_get_type ()) +#define OSTREE_MUTABLE_TREE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_MUTABLE_TREE, OstreeMutableTree)) +#define OSTREE_MUTABLE_TREE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_MUTABLE_TREE, OstreeMutableTreeClass)) +#define OSTREE_IS_MUTABLE_TREE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_MUTABLE_TREE)) +#define OSTREE_IS_MUTABLE_TREE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_MUTABLE_TREE)) +#define OSTREE_MUTABLE_TREE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_MUTABLE_TREE, OstreeMutableTreeClass)) + +typedef struct OstreeMutableTreeClass OstreeMutableTreeClass; + +typedef struct { + gboolean in_files; + GHashTableIter iter; +} OstreeMutableTreeIter; + +struct OstreeMutableTreeClass +{ + GObjectClass parent_class; +}; + +_OSTREE_PUBLIC +GType ostree_mutable_tree_get_type (void) G_GNUC_CONST; + +_OSTREE_PUBLIC +OstreeMutableTree *ostree_mutable_tree_new (void); + +_OSTREE_PUBLIC +OstreeMutableTree * ostree_mutable_tree_new_from_checksum (OstreeRepo *repo, + const char *contents_checksum, + const char *metadata_checksum); + +_OSTREE_PUBLIC +void ostree_mutable_tree_set_metadata_checksum (OstreeMutableTree *self, + const char *checksum); + +_OSTREE_PUBLIC +const char *ostree_mutable_tree_get_metadata_checksum (OstreeMutableTree *self); + +_OSTREE_PUBLIC +void ostree_mutable_tree_set_contents_checksum (OstreeMutableTree *self, + const char *checksum); + +_OSTREE_PUBLIC +const char *ostree_mutable_tree_get_contents_checksum (OstreeMutableTree *self); + +_OSTREE_PUBLIC +gboolean ostree_mutable_tree_replace_file (OstreeMutableTree *self, + const char *name, + const char *checksum, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_mutable_tree_remove (OstreeMutableTree *self, + const char *name, + gboolean allow_noent, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_mutable_tree_ensure_dir (OstreeMutableTree *self, + const char *name, + OstreeMutableTree **out_subdir, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_mutable_tree_lookup (OstreeMutableTree *self, + const char *name, + char **out_file_checksum, + OstreeMutableTree **out_subdir, + GError **error); + +_OSTREE_PUBLIC +gboolean +ostree_mutable_tree_ensure_parent_dirs (OstreeMutableTree *self, + GPtrArray *split_path, + const char *metadata_checksum, + OstreeMutableTree **out_parent, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_mutable_tree_walk (OstreeMutableTree *self, + GPtrArray *split_path, + guint start, + OstreeMutableTree **out_subdir, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_mutable_tree_fill_empty_from_dirtree (OstreeMutableTree *self, + OstreeRepo *repo, + const char *contents_checksum, + const char *metadata_checksum); + +_OSTREE_PUBLIC +gboolean +ostree_mutable_tree_check_error (OstreeMutableTree *self, + GError **error); + +_OSTREE_PUBLIC +GHashTable * ostree_mutable_tree_get_subdirs (OstreeMutableTree *self); +_OSTREE_PUBLIC +GHashTable * ostree_mutable_tree_get_files (OstreeMutableTree *self); + +G_END_DECLS diff --git a/src/libostree/ostree-ref.c b/src/libostree/ostree-ref.c new file mode 100644 index 0000000..ea372b8 --- /dev/null +++ b/src/libostree/ostree-ref.c @@ -0,0 +1,194 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-core.h" +#include "ostree-core-private.h" +#include "ostree-ref.h" + +G_DEFINE_BOXED_TYPE (OstreeCollectionRef, ostree_collection_ref, + ostree_collection_ref_dup, ostree_collection_ref_free) + +/** + * ostree_collection_ref_new: + * @collection_id: (nullable): a collection ID, or %NULL for a plain ref + * @ref_name: a ref name + * + * Create a new #OstreeCollectionRef containing (@collection_id, @ref_name). If + * @collection_id is %NULL, this is equivalent to a plain ref name string (not a + * refspec; no remote name is included), which can be used for non-P2P + * operations. + * + * Returns: (transfer full) (nullable): a new #OstreeCollectionRef + * Since: 2018.6 + */ +OstreeCollectionRef * +ostree_collection_ref_new (const gchar *collection_id, + const gchar *ref_name) +{ + g_autoptr(OstreeCollectionRef) collection_ref = NULL; + + g_return_val_if_fail (collection_id == NULL || + ostree_validate_collection_id (collection_id, NULL), NULL); + g_return_val_if_fail (ostree_validate_rev (ref_name, NULL), NULL); + + collection_ref = g_new0 (OstreeCollectionRef, 1); + collection_ref->collection_id = g_strdup (collection_id); + collection_ref->ref_name = g_strdup (ref_name); + + return g_steal_pointer (&collection_ref); +} + +/** + * ostree_collection_ref_dup: + * @ref: (not nullable): an #OstreeCollectionRef + * + * Create a copy of the given @ref. + * + * Returns: (transfer full): a newly allocated copy of @ref + * Since: 2018.6 + */ +OstreeCollectionRef * +ostree_collection_ref_dup (const OstreeCollectionRef *ref) +{ + g_return_val_if_fail (ref != NULL, NULL); + + return ostree_collection_ref_new (ref->collection_id, ref->ref_name); +} + +/** + * ostree_collection_ref_free: + * @ref: (transfer full): an #OstreeCollectionRef + * + * Free the given @ref. + * + * Since: 2018.6 + */ +void +ostree_collection_ref_free (OstreeCollectionRef *ref) +{ + g_return_if_fail (ref != NULL); + + g_free (ref->collection_id); + g_free (ref->ref_name); + g_free (ref); +} + +/** + * ostree_collection_ref_hash: + * @ref: (not nullable): an #OstreeCollectionRef + * + * Hash the given @ref. This function is suitable for use with #GHashTable. + * @ref must be non-%NULL. + * + * Returns: hash value for @ref + * Since: 2018.6 + */ +guint +ostree_collection_ref_hash (gconstpointer ref) +{ + const OstreeCollectionRef *_ref = ref; + + if (_ref->collection_id != NULL) + return g_str_hash (_ref->collection_id) ^ g_str_hash (_ref->ref_name); + else + return g_str_hash (_ref->ref_name); +} + +/** + * ostree_collection_ref_equal: + * @ref1: (not nullable): an #OstreeCollectionRef + * @ref2 : (not nullable): another #OstreeCollectionRef + * + * Compare @ref1 and @ref2 and return %TRUE if they have the same collection ID and + * ref name, and %FALSE otherwise. Both @ref1 and @ref2 must be non-%NULL. + * + * Returns: %TRUE if @ref1 and @ref2 are equal, %FALSE otherwise + * Since: 2018.6 + */ +gboolean +ostree_collection_ref_equal (gconstpointer ref1, + gconstpointer ref2) +{ + const OstreeCollectionRef *_ref1 = ref1, *_ref2 = ref2; + + return (g_strcmp0 (_ref1->collection_id, _ref2->collection_id) == 0 && + g_strcmp0 (_ref1->ref_name, _ref2->ref_name) == 0); +} + +/** + * ostree_collection_ref_dupv: + * @refs: (array zero-terminated=1): %NULL-terminated array of #OstreeCollectionRefs + * + * Copy an array of #OstreeCollectionRefs, including deep copies of all its + * elements. @refs must be %NULL-terminated; it may be empty, but must not be + * %NULL. + * + * Returns: (transfer full) (array zero-terminated=1): a newly allocated copy of @refs + * Since: 2018.6 + */ +OstreeCollectionRef ** +ostree_collection_ref_dupv (const OstreeCollectionRef * const *refs) +{ + gsize i, n_refs = g_strv_length ((gchar **) refs); /* hack */ + g_auto(OstreeCollectionRefv) new_refs = NULL; + + g_return_val_if_fail (refs != NULL, NULL); + + new_refs = g_new0 (OstreeCollectionRef*, n_refs + 1); + + for (i = 0; i < n_refs; i++) + new_refs[i] = ostree_collection_ref_dup (refs[i]); + new_refs[i] = NULL; + + return g_steal_pointer (&new_refs); +} + +/** + * ostree_collection_ref_freev: + * @refs: (transfer full) (array zero-terminated=1): an array of #OstreeCollectionRefs + * + * Free the given array of @refs, including freeing all its elements. @refs + * must be %NULL-terminated; it may be empty, but must not be %NULL. + * + * Since: 2018.6 + */ +void +ostree_collection_ref_freev (OstreeCollectionRef **refs) +{ + gsize i; + + g_return_if_fail (refs != NULL); + + for (i = 0; refs[i] != NULL; i++) + ostree_collection_ref_free (refs[i]); + g_free (refs); +} diff --git a/src/libostree/ostree-ref.h b/src/libostree/ostree-ref.h new file mode 100644 index 0000000..8df685e --- /dev/null +++ b/src/libostree/ostree-ref.h @@ -0,0 +1,89 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "ostree-types.h" + +G_BEGIN_DECLS + +/** + * OstreeCollectionRef: + * @collection_id: (nullable): collection ID which provided the ref, or %NULL if there + * is no associated collection + * @ref_name: ref name + * + * A structure which globally uniquely identifies a ref as the tuple + * (@collection_id, @ref_name). For backwards compatibility, @collection_id may be %NULL, + * indicating a ref name which is not globally unique. + * + * Since: 2018.6 + */ +typedef struct +{ + gchar *collection_id; /* (nullable) */ + gchar *ref_name; /* (not nullable) */ +} OstreeCollectionRef; + +_OSTREE_PUBLIC +GType ostree_collection_ref_get_type (void); + +_OSTREE_PUBLIC +OstreeCollectionRef *ostree_collection_ref_new (const gchar *collection_id, + const gchar *ref_name); +_OSTREE_PUBLIC +OstreeCollectionRef *ostree_collection_ref_dup (const OstreeCollectionRef *ref); +_OSTREE_PUBLIC +void ostree_collection_ref_free (OstreeCollectionRef *ref); + +_OSTREE_PUBLIC +guint ostree_collection_ref_hash (gconstpointer ref); +_OSTREE_PUBLIC +gboolean ostree_collection_ref_equal (gconstpointer ref1, + gconstpointer ref2); + +_OSTREE_PUBLIC +OstreeCollectionRef **ostree_collection_ref_dupv (const OstreeCollectionRef * const *refs); +_OSTREE_PUBLIC +void ostree_collection_ref_freev (OstreeCollectionRef **refs); + +/** + * OstreeCollectionRefv: + * + * A %NULL-terminated array of #OstreeCollectionRef instances, designed to + * be used with g_auto(): + * + * |[ + * g_auto(OstreeCollectionRefv) refs = NULL; + * ]| + * + * Since: 2018.6 + */ +typedef OstreeCollectionRef** OstreeCollectionRefv; + +G_END_DECLS diff --git a/src/libostree/ostree-remote-private.h b/src/libostree/ostree-remote-private.h new file mode 100644 index 0000000..061412d --- /dev/null +++ b/src/libostree/ostree-remote-private.h @@ -0,0 +1,63 @@ +/* + * Copyright © 2011 Colin Walters + * Copyright © 2015 Red Hat, Inc. + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Colin Walters + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "libglnx.h" +#include "ostree-remote.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +/* @refspec_name is set if this is a dynamic remote. It’s the name of the static + * remote which this one inherits from, and is what should be used in refspecs + * for pulls from this remote. If it’s %NULL, @name should be used instead. */ +struct OstreeRemote { + volatile int ref_count; + char *name; /* (not nullable) */ + char *refspec_name; /* (nullable) */ + char *group; /* group name in options (not nullable) */ + char *keyring; /* keyring name ($refspec_name.trustedkeys.gpg) (not nullable) */ + GFile *file; /* NULL if remote defined in repo/config */ + GKeyFile *options; +}; + +G_GNUC_INTERNAL +OstreeRemote *ostree_remote_new (const gchar *name); +G_GNUC_INTERNAL +OstreeRemote *ostree_remote_new_dynamic (const gchar *name, + const gchar *refspec_name); + +G_GNUC_INTERNAL +OstreeRemote *ostree_remote_new_from_keyfile (GKeyFile *keyfile, + const gchar *group); + +G_END_DECLS diff --git a/src/libostree/ostree-remote.c b/src/libostree/ostree-remote.c new file mode 100644 index 0000000..2b068e1 --- /dev/null +++ b/src/libostree/ostree-remote.c @@ -0,0 +1,201 @@ +/* + * Copyright © 2011 Colin Walters + * Copyright © 2015 Red Hat, Inc. + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Colin Walters + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ostree-remote.h" +#include "ostree-remote-private.h" +#include "ot-keyfile-utils.h" + +/** + * SECTION:remote + * + * The #OstreeRemote structure represents the configuration for a single remote + * repository. Currently, all configuration is handled internally, and + * #OstreeRemote objects are represented by their textual name handle, or by an + * opaque pointer (which can be reference counted if needed). + * + * #OstreeRemote provides configuration for accessing a remote, but does not + * provide the results of accessing a remote, such as information about what + * refs are currently on a remote, or the commits they currently point to. Use + * #OstreeRepo in combination with an #OstreeRemote to query that information. + * + * Since: 2018.6 + */ + +OstreeRemote * +ostree_remote_new (const gchar *name) +{ + return ostree_remote_new_dynamic (name, NULL); +} + +OstreeRemote * +ostree_remote_new_dynamic (const gchar *name, + const gchar *refspec_name) +{ + OstreeRemote *remote; + + g_return_val_if_fail (name != NULL && *name != '\0', NULL); + g_return_val_if_fail (refspec_name == NULL || *refspec_name != '\0', NULL); + + remote = g_slice_new0 (OstreeRemote); + remote->ref_count = 1; + remote->name = g_strdup (name); + remote->refspec_name = g_strdup (refspec_name); + remote->group = g_strdup_printf ("remote \"%s\"", (refspec_name != NULL) ? refspec_name : name); + remote->keyring = g_strdup_printf ("%s.trustedkeys.gpg", (refspec_name != NULL) ? refspec_name : name); + remote->options = g_key_file_new (); + + return remote; +} + +OstreeRemote * +ostree_remote_new_from_keyfile (GKeyFile *keyfile, + const gchar *group) +{ + g_autoptr(GMatchInfo) match = NULL; + OstreeRemote *remote; + g_autofree gchar *name = NULL; + + static gsize regex_initialized; + static GRegex *regex; + + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^remote \"(.+)\"$", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + /* Sanity check */ + g_return_val_if_fail (g_key_file_has_group (keyfile, group), NULL); + + /* If group name doesn't fit the pattern, fail. */ + if (!g_regex_match (regex, group, 0, &match)) + return NULL; + + name = g_match_info_fetch (match, 1); + remote = ostree_remote_new (name); + + ot_keyfile_copy_group (keyfile, remote->options, group); + + return remote; +} + +/** + * ostree_remote_ref: + * @remote: an #OstreeRemote + * + * Increase the reference count on the given @remote. + * + * Returns: (transfer full): a copy of @remote, for convenience + * Since: 2018.6 + */ +OstreeRemote * +ostree_remote_ref (OstreeRemote *remote) +{ + gint refcount; + g_return_val_if_fail (remote != NULL, NULL); + refcount = g_atomic_int_add (&remote->ref_count, 1); + g_assert (refcount > 0); + return remote; +} + +/** + * ostree_remote_unref: + * @remote: (transfer full): an #OstreeRemote + * + * Decrease the reference count on the given @remote and free it if the + * reference count reaches 0. + * + * Since: 2018.6 + */ +void +ostree_remote_unref (OstreeRemote *remote) +{ + g_return_if_fail (remote != NULL); + g_return_if_fail (remote->ref_count > 0); + + if (g_atomic_int_dec_and_test (&remote->ref_count)) + { + g_clear_pointer (&remote->name, g_free); + g_clear_pointer (&remote->refspec_name, g_free); + g_clear_pointer (&remote->group, g_free); + g_clear_pointer (&remote->keyring, g_free); + g_clear_object (&remote->file); + g_clear_pointer (&remote->options, g_key_file_free); + g_slice_free (OstreeRemote, remote); + } +} + +G_DEFINE_BOXED_TYPE(OstreeRemote, ostree_remote, + ostree_remote_ref, + ostree_remote_unref); + +/** + * ostree_remote_get_name: + * @remote: an #OstreeRemote + * + * Get the human-readable name of the remote. This is what the user configured, + * if the remote was explicitly configured; and will otherwise be a stable, + * arbitrary, string. + * + * Returns: remote’s name + * Since: 2018.6 + */ +const gchar * +ostree_remote_get_name (OstreeRemote *remote) +{ + g_return_val_if_fail (remote != NULL, NULL); + g_return_val_if_fail (remote->ref_count > 0, NULL); + + return remote->name; +} + +/** + * ostree_remote_get_url: + * @remote: an #OstreeRemote + * + * Get the URL from the remote. + * + * Returns: (transfer full): the remote's URL + * Since: 2018.6 + */ +gchar * +ostree_remote_get_url (OstreeRemote *remote) +{ + g_return_val_if_fail (remote != NULL, NULL); + g_return_val_if_fail (remote->ref_count > 0, NULL); + + return g_key_file_get_string (remote->options, remote->group, "url", NULL); +} diff --git a/src/libostree/ostree-remote.h b/src/libostree/ostree-remote.h new file mode 100644 index 0000000..a785b4e --- /dev/null +++ b/src/libostree/ostree-remote.h @@ -0,0 +1,61 @@ +/* + * Copyright © 2011 Colin Walters + * Copyright © 2015 Red Hat, Inc. + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Colin Walters + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "ostree-types.h" + +G_BEGIN_DECLS + +/** + * OstreeRemote: + * + * This represents the configuration for a single remote repository. Currently, + * remotes can only be passed around as (reference counted) opaque handles. In + * future, more API may be added to create and interrogate them. + * + * Since: 2018.6 + */ + +_OSTREE_PUBLIC +GType ostree_remote_get_type (void) G_GNUC_CONST; +_OSTREE_PUBLIC +OstreeRemote *ostree_remote_ref (OstreeRemote *remote); +_OSTREE_PUBLIC +void ostree_remote_unref (OstreeRemote *remote); + +_OSTREE_PUBLIC +const gchar *ostree_remote_get_name (OstreeRemote *remote); + +_OSTREE_PUBLIC +gchar *ostree_remote_get_url (OstreeRemote *remote); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c new file mode 100644 index 0000000..dc36370 --- /dev/null +++ b/src/libostree/ostree-repo-checkout.c @@ -0,0 +1,1503 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include +#include +#include +#include "otutil.h" + +#include "ostree-repo-file.h" +#include "ostree-sepolicy-private.h" +#include "ostree-core-private.h" +#include "ostree-repo-private.h" + +#define WHITEOUT_PREFIX ".wh." +#define OPAQUE_WHITEOUT_NAME ".wh..wh..opq" + +/* Per-checkout call state/caching */ +typedef struct { + GString *path_buf; /* buffer for real path if filtering enabled */ + GString *selabel_path_buf; /* buffer for selinux path if labeling enabled; this may be + the same buffer as path_buf */ +} CheckoutState; + +static void +checkout_state_clear (CheckoutState *state) +{ + if (state->path_buf) + g_string_free (state->path_buf, TRUE); + if (state->selabel_path_buf && (state->selabel_path_buf != state->path_buf)) + g_string_free (state->selabel_path_buf, TRUE); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(CheckoutState, checkout_state_clear) + +static gboolean +checkout_object_for_uncompressed_cache (OstreeRepo *self, + const char *loose_path, + GFileInfo *src_info, + GInputStream *content, + GCancellable *cancellable, + GError **error) +{ + /* Don't make setuid files in uncompressed cache */ + guint32 file_mode = g_file_info_get_attribute_uint32 (src_info, "unix::mode"); + file_mode &= ~(S_ISUID|S_ISGID); + + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (self->tmp_dir_fd, ".", O_WRONLY | O_CLOEXEC, + &tmpf, error)) + return FALSE; + g_autoptr(GOutputStream) temp_out = g_unix_output_stream_new (tmpf.fd, FALSE); + + if (g_output_stream_splice (temp_out, content, 0, cancellable, error) < 0) + return FALSE; + + if (!g_output_stream_flush (temp_out, cancellable, error)) + return FALSE; + + if (!self->disable_fsync) + { + if (TEMP_FAILURE_RETRY (fsync (tmpf.fd)) < 0) + return glnx_throw_errno (error); + } + + if (!g_output_stream_close (temp_out, cancellable, error)) + return FALSE; + + if (!glnx_fchmod (tmpf.fd, file_mode, error)) + return FALSE; + + if (self->uncompressed_objects_dir_fd == -1) + { + if (!glnx_shutil_mkdir_p_at (self->repo_dir_fd, "uncompressed-objects-cache", + DEFAULT_DIRECTORY_MODE, cancellable, error)) + return FALSE; + if (!glnx_opendirat (self->repo_dir_fd, "uncompressed-objects-cache", TRUE, + &self->uncompressed_objects_dir_fd, + error)) + return FALSE; + } + + if (!_ostree_repo_ensure_loose_objdir_at (self->uncompressed_objects_dir_fd, + loose_path, + cancellable, error)) + return FALSE; + + if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST, + self->uncompressed_objects_dir_fd, loose_path, + error)) + return FALSE; + + return TRUE; +} + +static gboolean +fsync_is_enabled (OstreeRepo *self, + OstreeRepoCheckoutAtOptions *options) +{ + return options->enable_fsync; +} + +static gboolean +write_regular_file_content (OstreeRepo *self, + OstreeRepoCheckoutAtOptions *options, + int outfd, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream *input, + GCancellable *cancellable, + GError **error) +{ + const OstreeRepoCheckoutMode mode = options->mode; + g_autoptr(GOutputStream) outstream = NULL; + + if (G_IS_FILE_DESCRIPTOR_BASED (input)) + { + int infd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*) input); + guint64 len = g_file_info_get_size (file_info); + + if (glnx_regfile_copy_bytes (infd, outfd, (off_t)len) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); + } + else + { + outstream = g_unix_output_stream_new (outfd, FALSE); + if (g_output_stream_splice (outstream, input, 0, + cancellable, error) < 0) + return FALSE; + + if (!g_output_stream_flush (outstream, cancellable, error)) + return FALSE; + } + + if (mode != OSTREE_REPO_CHECKOUT_MODE_USER) + { + if (TEMP_FAILURE_RETRY (fchown (outfd, g_file_info_get_attribute_uint32 (file_info, "unix::uid"), + g_file_info_get_attribute_uint32 (file_info, "unix::gid"))) < 0) + return glnx_throw_errno_prefix (error, "fchown"); + + if (xattrs) + { + if (!glnx_fd_set_all_xattrs (outfd, xattrs, cancellable, error)) + return FALSE; + } + } + + guint32 file_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + + /* Don't make setuid files on checkout when we're doing --user */ + if (mode == OSTREE_REPO_CHECKOUT_MODE_USER) + file_mode &= ~(S_ISUID|S_ISGID); + + if (TEMP_FAILURE_RETRY (fchmod (outfd, file_mode)) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + if (fsync_is_enabled (self, options)) + { + if (fsync (outfd) == -1) + return glnx_throw_errno_prefix (error, "fsync"); + } + + if (outstream) + { + if (!g_output_stream_close (outstream, cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/* + * Create a copy of a file, supporting optional union/add behavior. + */ +static gboolean +create_file_copy_from_input_at (OstreeRepo *repo, + OstreeRepoCheckoutAtOptions *options, + CheckoutState *state, + const char *checksum, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream *input, + int destination_dfd, + const char *destination_name, + GCancellable *cancellable, + GError **error) +{ + const gboolean sepolicy_enabled = options->sepolicy && !repo->disable_xattrs; + g_autoptr(GVariant) modified_xattrs = NULL; + + /* If we're doing SELinux labeling, prepare it */ + if (sepolicy_enabled) + { + /* If doing sepolicy path-based labeling, we don't want to set the + * security.selinux attr via the generic xattr paths in either the symlink + * or regfile cases, so filter it out. + */ + modified_xattrs = _ostree_filter_selinux_xattr (xattrs); + xattrs = modified_xattrs; + } + + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) + { + g_auto(OstreeSepolicyFsCreatecon) fscreatecon = { 0, }; + + if (sepolicy_enabled) + { + /* For symlinks, since we don't have O_TMPFILE, we use setfscreatecon() */ + if (!_ostree_sepolicy_preparefscreatecon (&fscreatecon, options->sepolicy, + state->selabel_path_buf->str, + g_file_info_get_attribute_uint32 (file_info, "unix::mode"), + error)) + return FALSE; + } + + const char *target = g_file_info_get_symlink_target (file_info); + if (symlinkat (target, destination_dfd, destination_name) < 0) + { + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "symlinkat"); + + /* Handle union/add behaviors if we get EEXIST */ + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + return glnx_throw_errno_prefix (error, "symlinkat"); + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + { + /* For unioning, we further bifurcate a bit; for the "process whiteouts" + * mode which is really "Docker/OCI", we need to match their semantics + * and handle replacing a directory with a symlink. See also equivalent + * bits for regular files in checkout_file_hardlink(). + */ + if (options->process_whiteouts) + { + if (!glnx_shutil_rm_rf_at (destination_dfd, destination_name, NULL, error)) + return FALSE; + } + else + { + if (unlinkat (destination_dfd, destination_name, 0) < 0) + { + if (G_UNLIKELY (errno != ENOENT)) + return glnx_throw_errno_prefix (error, "unlinkat(%s)", destination_name); + } + } + if (symlinkat (target, destination_dfd, destination_name) < 0) + return glnx_throw_errno_prefix (error, "symlinkat"); + } + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + /* Note early return - we don't want to set the xattrs below */ + return TRUE; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + { + /* See the comments for the hardlink version of this + * for why we do this. + */ + struct stat dest_stbuf; + if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (S_ISLNK (dest_stbuf.st_mode)) + { + g_autofree char *dest_target = + glnx_readlinkat_malloc (destination_dfd, destination_name, + cancellable, error); + if (!dest_target) + return FALSE; + /* In theory we could also compare xattrs...but eh */ + if (g_str_equal (dest_target, target)) + return TRUE; + } + errno = EEXIST; + return glnx_throw_errno_prefix (error, "symlinkat"); + } + } + } + + /* Process ownership and xattrs now that we made the link */ + if (options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) + { + if (TEMP_FAILURE_RETRY (fchownat (destination_dfd, destination_name, + g_file_info_get_attribute_uint32 (file_info, "unix::uid"), + g_file_info_get_attribute_uint32 (file_info, "unix::gid"), + AT_SYMLINK_NOFOLLOW)) == -1) + return glnx_throw_errno_prefix (error, "fchownat"); + + if (xattrs != NULL && + !glnx_dfd_name_set_all_xattrs (destination_dfd, destination_name, + xattrs, cancellable, error)) + return FALSE; + } + } + else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) + { + g_auto(GLnxTmpfile) tmpf = { 0, }; + + if (!glnx_open_tmpfile_linkable_at (destination_dfd, ".", O_WRONLY | O_CLOEXEC, + &tmpf, error)) + return FALSE; + + if (sepolicy_enabled && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) + { + g_autofree char *label = NULL; + if (!ostree_sepolicy_get_label (options->sepolicy, state->selabel_path_buf->str, + g_file_info_get_attribute_uint32 (file_info, "unix::mode"), + &label, cancellable, error)) + return FALSE; + + if (fsetxattr (tmpf.fd, "security.selinux", label, strlen (label), 0) < 0) + return glnx_throw_errno_prefix (error, "Setting security.selinux"); + } + + if (!write_regular_file_content (repo, options, tmpf.fd, file_info, xattrs, input, + cancellable, error)) + return FALSE; + + /* The add/union/none behaviors map directly to GLnxLinkTmpfileReplaceMode */ + GLnxLinkTmpfileReplaceMode replace_mode = GLNX_LINK_TMPFILE_NOREPLACE; + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + /* Handled above */ + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + /* Special case OCI/Docker - see similar code in checkout_file_hardlink() + * and above for symlinks. + */ + if (options->process_whiteouts) + { + if (!glnx_shutil_rm_rf_at (destination_dfd, destination_name, NULL, error)) + return FALSE; + /* Inherit the NOREPLACE default...we deleted whatever's there */ + } + else + replace_mode = GLNX_LINK_TMPFILE_REPLACE; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + replace_mode = GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + { + replace_mode = GLNX_LINK_TMPFILE_NOREPLACE; + struct stat dest_stbuf; + if (!glnx_fstatat_allow_noent (destination_dfd, destination_name, &dest_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == 0) + { + /* We do a checksum comparison; see also equivalent code in + * checkout_file_hardlink(). + */ + OstreeChecksumFlags flags = 0; + if (repo->disable_xattrs) + flags |= OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS; + + g_autofree char *actual_checksum = NULL; + if (!ostree_checksum_file_at (destination_dfd, destination_name, + &dest_stbuf, OSTREE_OBJECT_TYPE_FILE, + flags, &actual_checksum, cancellable, error)) + return FALSE; + + if (g_str_equal (checksum, actual_checksum)) + return TRUE; + + /* Otherwise, fall through and do the link, we should + * get EEXIST. + */ + } + } + break; + } + + if (!glnx_link_tmpfile_at (&tmpf, replace_mode, + destination_dfd, destination_name, + error)) + return FALSE; + } + else + g_assert_not_reached (); + + return TRUE; +} + +typedef enum { + HARDLINK_RESULT_NOT_SUPPORTED, + HARDLINK_RESULT_SKIP_EXISTED, + HARDLINK_RESULT_LINKED +} HardlinkResult; + +/* Used for OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES. In + * order to atomically replace a target, we add a new link + * in self->tmp_dir_fd, with a name placed into the mutable + * buffer @tmpname. + */ +static gboolean +hardlink_add_tmp_name (OstreeRepo *self, + int srcfd, + const char *loose_path, + char *tmpname, + GCancellable *cancellable, + GError **error) +{ + const int max_attempts = 128; + guint i; + + for (i = 0; i < max_attempts; i++) + { + glnx_gen_temp_name (tmpname); + if (linkat (srcfd, loose_path, self->tmp_dir_fd, tmpname, 0) < 0) + { + if (errno == EEXIST) + continue; + else + return glnx_throw_errno_prefix (error, "linkat"); + } + else + break; + } + if (i == max_attempts) + return glnx_throw (error, "Exhausted attempts to make temporary hardlink"); + + return TRUE; +} + +static gboolean +checkout_file_hardlink (OstreeRepo *self, + const char *checksum, + OstreeRepoCheckoutAtOptions *options, + const char *loose_path, + int destination_dfd, + const char *destination_name, + gboolean allow_noent, + HardlinkResult *out_result, + GCancellable *cancellable, + GError **error) +{ + HardlinkResult ret_result = HARDLINK_RESULT_NOT_SUPPORTED; + int srcfd = _ostree_repo_mode_is_bare (self->mode) ? + self->objects_dir_fd : self->uncompressed_objects_dir_fd; + + if (srcfd == -1) + { + /* Fall through; we don't have an uncompressed object cache */ + } + else if (linkat (srcfd, loose_path, destination_dfd, destination_name, 0) == 0) + ret_result = HARDLINK_RESULT_LINKED; + else if (!options->no_copy_fallback && (errno == EMLINK || errno == EXDEV || errno == EPERM)) + { + /* EMLINK, EXDEV and EPERM shouldn't be fatal; we just can't do the + * optimization of hardlinking instead of copying. + */ + } + else if (allow_noent && errno == ENOENT) + { + /* Fall through */ + } + else if (errno == EEXIST) + { + /* When we get EEXIST, we need to handle the different overwrite modes. */ + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + /* Just throw */ + return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name); + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + /* In this mode, we keep existing content. Distinguish this case though to + * avoid inserting into the devino cache. + */ + ret_result = HARDLINK_RESULT_SKIP_EXISTED; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + { + /* In both union-files and union-identical, see if the src/target are + * already hardlinked. If they are, we're done. + * + * If not, for union-identical we error out, which is what + * rpm-ostree wants for package layering. + * https://github.com/projectatomic/rpm-ostree/issues/982 + * This should be similar to the librpm version: + * https://github.com/rpm-software-management/rpm/blob/e3cd2bc85e0578f158d14e6f9624eb955c32543b/lib/rpmfi.c#L921 + * in rpmfilesCompare(). + * + * For union-files, we make a temporary link, then rename() it + * into place. + */ + struct stat src_stbuf; + if (!glnx_fstatat (srcfd, loose_path, &src_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + struct stat dest_stbuf; + if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + gboolean is_identical = + (src_stbuf.st_dev == dest_stbuf.st_dev && + src_stbuf.st_ino == dest_stbuf.st_ino); + if (!is_identical && (_ostree_stbuf_equal (&src_stbuf, &dest_stbuf))) + { + /* As a last resort, do a checksum comparison. This is the case currently + * with rpm-ostree pkg layering where we overlay from the pkgcache repo onto + * a tree checked out from the system repo. Once those are united, we + * shouldn't hit this anymore. https://github.com/ostreedev/ostree/pull/1258 + * */ + OstreeChecksumFlags flags = 0; + if (self->disable_xattrs) + flags |= OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS; + + g_autofree char *actual_checksum = NULL; + if (!ostree_checksum_file_at (destination_dfd, destination_name, + &dest_stbuf, OSTREE_OBJECT_TYPE_FILE, + flags, &actual_checksum, cancellable, error)) + return FALSE; + + is_identical = g_str_equal (checksum, actual_checksum); + } + if (is_identical) + ret_result = HARDLINK_RESULT_SKIP_EXISTED; + else if (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES) + { + char *tmpname = strdupa ("checkout-union-XXXXXX"); + /* Make a link with a temp name */ + if (!hardlink_add_tmp_name (self, srcfd, loose_path, tmpname, cancellable, error)) + return FALSE; + /* For OCI/Docker mode, we need to handle replacing a directory with a regular + * file. See also the equivalent code for symlinks above. + */ + if (options->process_whiteouts) + { + if (!glnx_shutil_rm_rf_at (destination_dfd, destination_name, NULL, error)) + return FALSE; + } + /* Rename it into place - for non-OCI this will overwrite files but not directories */ + if (!glnx_renameat (self->tmp_dir_fd, tmpname, destination_dfd, destination_name, error)) + return FALSE; + ret_result = HARDLINK_RESULT_LINKED; + } + else + { + g_assert_cmpint (options->overwrite_mode, ==, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL); + return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name); + } + break; + } + } + } + else + { + return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name); + } + + if (out_result) + *out_result = ret_result; + return TRUE; +} + +static gboolean +checkout_one_file_at (OstreeRepo *repo, + OstreeRepoCheckoutAtOptions *options, + CheckoutState *state, + const char *checksum, + int destination_dfd, + const char *destination_name, + GCancellable *cancellable, + GError **error) +{ + /* Validate this up front to prevent path traversal attacks */ + if (!ot_util_filename_validate (destination_name, error)) + return FALSE; + + gboolean need_copy = TRUE; + gboolean is_bare_user_symlink = FALSE; + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + + + /* FIXME - avoid the GFileInfo here */ + g_autoptr(GFileInfo) source_info = NULL; + if (!ostree_repo_load_file (repo, checksum, NULL, &source_info, NULL, + cancellable, error)) + return FALSE; + + if (options->filter) + { + /* use struct stat for when we can get rid of GFileInfo; though for now, we end up + * packing and unpacking in the non-archive case; blehh */ + struct stat stbuf = {0,}; + _ostree_gfileinfo_to_stbuf (source_info, &stbuf); + if (options->filter (repo, state->path_buf->str, &stbuf, options->filter_user_data) == + OSTREE_REPO_CHECKOUT_FILTER_SKIP) + return TRUE; /* Note early return */ + } + + const gboolean is_symlink = (g_file_info_get_file_type (source_info) == G_FILE_TYPE_SYMBOLIC_LINK); + const gboolean is_whiteout = (!is_symlink && options->process_whiteouts && + g_str_has_prefix (destination_name, WHITEOUT_PREFIX)); + const gboolean is_reg_zerosized = (!is_symlink && g_file_info_get_size (source_info) == 0); + + /* First, see if it's a Docker whiteout, + * https://github.com/docker/docker/blob/1a714e76a2cb9008cd19609059e9988ff1660b78/pkg/archive/whiteouts.go + */ + if (is_whiteout) + { + const char *name = destination_name + (sizeof (WHITEOUT_PREFIX) - 1); + + if (!name[0]) + return glnx_throw (error, "Invalid empty whiteout '%s'", name); + + g_assert (name[0] != '/'); /* Sanity */ + + if (!glnx_shutil_rm_rf_at (destination_dfd, name, cancellable, error)) + return FALSE; + + need_copy = FALSE; + } + else if (options->force_copy_zerosized && is_reg_zerosized) + { + need_copy = TRUE; + } + else if (!options->force_copy) + { + HardlinkResult hardlink_res = HARDLINK_RESULT_NOT_SUPPORTED; + /* Try to do a hardlink first, if it's a regular file. This also + * traverses all parent repos. + */ + OstreeRepo *current_repo = repo; + + while (current_repo) + { + /* TODO - Hoist this up to the toplevel at least for checking out from + * !parent; don't need to compute it for each file. + */ + gboolean repo_is_usermode = + current_repo->mode == OSTREE_REPO_MODE_BARE_USER || + current_repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY; + /* We're hardlinkable if the checkout mode matches the repo mode */ + gboolean is_hardlinkable = + (current_repo->mode == OSTREE_REPO_MODE_BARE + && options->mode == OSTREE_REPO_CHECKOUT_MODE_NONE) || + (repo_is_usermode && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER); + gboolean current_can_cache = (options->enable_uncompressed_cache + && current_repo->enable_uncompressed_cache); + gboolean is_archive_z2_with_cache = (current_repo->mode == OSTREE_REPO_MODE_ARCHIVE + && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER + && current_can_cache); + + /* NOTE: bare-user symlinks are not stored as symlinks; see + * https://github.com/ostreedev/ostree/commit/47c612e5a0688c3452a125655a245e8f4f01b2b0 + * as well as write_object(). + */ + is_bare_user_symlink = (repo_is_usermode && is_symlink); + const gboolean is_bare = is_hardlinkable && !is_bare_user_symlink; + + /* Verify if no_copy_fallback is set that we can hardlink, with a + * special exception for bare-user symlinks. + */ + if (options->no_copy_fallback && !is_hardlinkable && !is_bare_user_symlink) + return glnx_throw (error, + repo_is_usermode ? + "User repository mode requires user checkout mode to hardlink" : + "Bare repository mode cannot hardlink in user checkout mode"); + + /* But only under these conditions */ + if (is_bare || is_archive_z2_with_cache) + { + /* Override repo mode; for archive we're looking in + the cache, which is in "bare" form */ + _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, OSTREE_REPO_MODE_BARE); + if (!checkout_file_hardlink (current_repo, + checksum, + options, + loose_path_buf, + destination_dfd, destination_name, + TRUE, &hardlink_res, + cancellable, error)) + return FALSE; + + if (hardlink_res == HARDLINK_RESULT_LINKED && options->devino_to_csum_cache) + { + struct stat stbuf; + OstreeDevIno *key; + + if (TEMP_FAILURE_RETRY (fstatat (destination_dfd, destination_name, &stbuf, AT_SYMLINK_NOFOLLOW)) != 0) + return glnx_throw_errno (error); + + key = g_new (OstreeDevIno, 1); + key->dev = stbuf.st_dev; + key->ino = stbuf.st_ino; + memcpy (key->checksum, checksum, OSTREE_SHA256_STRING_LEN+1); + + g_hash_table_add ((GHashTable*)options->devino_to_csum_cache, key); + } + + if (hardlink_res != HARDLINK_RESULT_NOT_SUPPORTED) + break; + } + current_repo = current_repo->parent_repo; + } + /* Pacify clang-analyzer which sees us testing effectively if (repo == NULL) */ + g_assert (repo); + + need_copy = (hardlink_res == HARDLINK_RESULT_NOT_SUPPORTED); + } + + const gboolean can_cache = (options->enable_uncompressed_cache + && repo->enable_uncompressed_cache); + + g_autoptr(GInputStream) input = NULL; + g_autoptr(GVariant) xattrs = NULL; + + /* Ok, if we're archive and we didn't find an object, uncompress + * it now, stick it in the cache, and then hardlink to that. + */ + if (can_cache + && !is_whiteout + && !is_symlink + && !is_reg_zerosized + && need_copy + && repo->mode == OSTREE_REPO_MODE_ARCHIVE + && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER) + { + HardlinkResult hardlink_res = HARDLINK_RESULT_NOT_SUPPORTED; + + if (!ostree_repo_load_file (repo, checksum, &input, NULL, NULL, + cancellable, error)) + return FALSE; + + /* Overwrite any parent repo from earlier */ + _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, OSTREE_REPO_MODE_BARE); + + if (!checkout_object_for_uncompressed_cache (repo, loose_path_buf, + source_info, input, + cancellable, error)) + return glnx_prefix_error (error, "Unpacking loose object %s", checksum); + + g_clear_object (&input); + + /* Store the 2-byte objdir prefix (e.g. e3) in a set. The basic + * idea here is that if we had to unpack an object, it's very + * likely we're replacing some other object, so we may need a GC. + * + * This model ensures that we do work roughly proportional to + * the size of the changes. For example, we don't scan any + * directories if we didn't modify anything, meaning you can + * checkout the same tree multiple times very quickly. + * + * This is also scale independent; we don't hardcode e.g. looking + * at 1000 objects. + * + * The downside is that if we're unlucky, we may not free + * an object for quite some time. + */ + g_mutex_lock (&repo->cache_lock); + { + gpointer key = GUINT_TO_POINTER ((g_ascii_xdigit_value (checksum[0]) << 4) + + g_ascii_xdigit_value (checksum[1])); + if (repo->updated_uncompressed_dirs == NULL) + repo->updated_uncompressed_dirs = g_hash_table_new (NULL, NULL); + g_hash_table_add (repo->updated_uncompressed_dirs, key); + } + g_mutex_unlock (&repo->cache_lock); + + if (!checkout_file_hardlink (repo, checksum, options, loose_path_buf, + destination_dfd, destination_name, + FALSE, &hardlink_res, + cancellable, error)) + return glnx_prefix_error (error, "Using new cached uncompressed hardlink of %s to %s", checksum, destination_name); + + need_copy = (hardlink_res == HARDLINK_RESULT_NOT_SUPPORTED); + } + + /* Fall back to copy if we couldn't hardlink */ + if (need_copy) + { + /* Bare user mode can't hardlink symlinks, so we need to do a copy for + * those. (Although in the future we could hardlink inside checkouts) This + * assertion is intended to ensure that for regular files at least, we + * succeeded at hardlinking above. + */ + if (options->no_copy_fallback) + g_assert (is_bare_user_symlink || is_reg_zerosized); + if (!ostree_repo_load_file (repo, checksum, &input, NULL, &xattrs, + cancellable, error)) + return FALSE; + + if (!create_file_copy_from_input_at (repo, options, state, checksum, source_info, xattrs, input, + destination_dfd, destination_name, + cancellable, error)) + return glnx_prefix_error (error, "Copy checkout of %s to %s", checksum, destination_name); + + if (input) + { + if (!g_input_stream_close (input, cancellable, error)) + return FALSE; + } + } + + return TRUE; +} + +static inline void +push_path_element_once (GString *buf, + const char *name, + gboolean is_dir) +{ + g_string_append (buf, name); + if (is_dir) + g_string_append_c (buf, '/'); +} + +static inline void +push_path_element (OstreeRepoCheckoutAtOptions *options, + CheckoutState *state, + const char *name, + gboolean is_dir) +{ + if (state->path_buf) + push_path_element_once (state->path_buf, name, is_dir); + if (state->selabel_path_buf && (state->selabel_path_buf != state->path_buf)) + push_path_element_once (state->selabel_path_buf, name, is_dir); +} + +static inline void +pop_path_element (OstreeRepoCheckoutAtOptions *options, + CheckoutState *state, + const char *name, + gboolean is_dir) +{ + const size_t n = strlen (name) + (is_dir ? 1 : 0); + if (state->path_buf) + g_string_truncate (state->path_buf, state->path_buf->len - n); + if (state->selabel_path_buf && (state->selabel_path_buf != state->path_buf)) + g_string_truncate (state->selabel_path_buf, state->selabel_path_buf->len - n); +} + +/* + * checkout_tree_at: + * @self: Repo + * @mode: Options controlling all files + * @state: Any state we're carrying through + * @overwrite_mode: Whether or not to overwrite files + * @destination_parent_fd: Place tree here + * @destination_name: Use this name for tree + * @source: Source tree + * @source_info: Source info + * @cancellable: Cancellable + * @error: Error + * + * Like ostree_repo_checkout_tree(), but check out @source into the + * relative @destination_name, located by @destination_parent_fd. + */ +static gboolean +checkout_tree_at_recurse (OstreeRepo *self, + OstreeRepoCheckoutAtOptions *options, + CheckoutState *state, + int destination_parent_fd, + const char *destination_name, + const char *dirtree_checksum, + const char *dirmeta_checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean did_exist = FALSE; + gboolean is_opaque_whiteout = FALSE; + const gboolean sepolicy_enabled = options->sepolicy && !self->disable_xattrs; + g_autoptr(GVariant) dirtree = NULL; + g_autoptr(GVariant) dirmeta = NULL; + g_autoptr(GVariant) xattrs = NULL; + g_autoptr(GVariant) modified_xattrs = NULL; + + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_DIR_TREE, + dirtree_checksum, &dirtree, error)) + return FALSE; + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_DIR_META, + dirmeta_checksum, &dirmeta, error)) + return FALSE; + + /* Parse OSTREE_OBJECT_TYPE_DIR_META */ + guint32 uid, gid, mode; + g_variant_get (dirmeta, "(uuu@a(ayay))", + &uid, &gid, &mode, + options->mode != OSTREE_REPO_CHECKOUT_MODE_USER ? &xattrs : NULL); + uid = GUINT32_FROM_BE (uid); + gid = GUINT32_FROM_BE (gid); + mode = GUINT32_FROM_BE (mode); + + if (options->filter) + { + struct stat stbuf = { 0, }; + stbuf.st_mode = mode; + stbuf.st_uid = uid; + stbuf.st_gid = gid; + if (options->filter (self, state->path_buf->str, &stbuf, options->filter_user_data) + == OSTREE_REPO_CHECKOUT_FILTER_SKIP) + return TRUE; /* Note early return */ + } + + if (options->process_whiteouts) + { + g_autoptr(GVariant) dir_file_contents = g_variant_get_child_value (dirtree, 0); + GVariantIter viter; + const char *fname; + g_autoptr(GVariant) contents_csum_v = NULL; + g_variant_iter_init (&viter, dir_file_contents); + while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, &contents_csum_v)) + { + is_opaque_whiteout = (g_str_equal (fname, OPAQUE_WHITEOUT_NAME)); + if (is_opaque_whiteout) + break; + } + contents_csum_v = NULL; /* iter_loop freed it */ + } + + /* First, make the directory. Push a new scope in case we end up using + * setfscreatecon(). + */ + { + g_auto(OstreeSepolicyFsCreatecon) fscreatecon = { 0, }; + + /* If we're doing SELinux labeling, prepare it */ + if (sepolicy_enabled) + { + /* We'll set the xattr via setfscreatecon(), so don't do it via generic xattrs below. */ + modified_xattrs = _ostree_filter_selinux_xattr (xattrs); + xattrs = modified_xattrs; + + if (!_ostree_sepolicy_preparefscreatecon (&fscreatecon, options->sepolicy, + state->selabel_path_buf->str, + mode, error)) + return FALSE; + } + + /* If it is an opaque whiteout, ensure the destination is empty first. */ + if (is_opaque_whiteout) + { + if (!glnx_shutil_rm_rf_at (destination_parent_fd, destination_name, cancellable, error)) + return FALSE; + } + + /* Create initially with mode 0700, then chown/chmod only when we're + * done. This avoids anyone else being able to operate on partially + * constructed dirs. + */ + if (TEMP_FAILURE_RETRY (mkdirat (destination_parent_fd, destination_name, 0700)) < 0) + { + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "mkdirat"); + + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + return glnx_throw_errno_prefix (error, "mkdirat"); + /* All of these cases are the same for directories */ + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + did_exist = TRUE; + break; + } + } + } + + glnx_autofd int destination_dfd = -1; + if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE, + &destination_dfd, error)) + return FALSE; + + struct stat repo_dfd_stat; + if (fstat (self->repo_dir_fd, &repo_dfd_stat) < 0) + return glnx_throw_errno (error); + struct stat destination_stat; + if (fstat (destination_dfd, &destination_stat) < 0) + return glnx_throw_errno (error); + + if (options->no_copy_fallback && repo_dfd_stat.st_dev != destination_stat.st_dev) + return glnx_throw (error, "Unable to do hardlink checkout across devices (src=%"G_GUINT64_FORMAT" destination=%"G_GUINT64_FORMAT")", + (guint64)repo_dfd_stat.st_dev, (guint64)destination_stat.st_dev); + + /* Set the xattrs if we created the dir */ + if (!did_exist && xattrs) + { + if (!glnx_fd_set_all_xattrs (destination_dfd, xattrs, cancellable, error)) + return FALSE; + } + + /* Process files in this subdir */ + { g_autoptr(GVariant) dir_file_contents = g_variant_get_child_value (dirtree, 0); + GVariantIter viter; + g_variant_iter_init (&viter, dir_file_contents); + const char *fname; + g_autoptr(GVariant) contents_csum_v = NULL; + while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, &contents_csum_v)) + { + push_path_element (options, state, fname, FALSE); + + char tmp_checksum[OSTREE_SHA256_STRING_LEN+1]; + _ostree_checksum_inplace_from_bytes_v (contents_csum_v, tmp_checksum); + + if (!checkout_one_file_at (self, options, state, + tmp_checksum, + destination_dfd, fname, + cancellable, error)) + return FALSE; + + pop_path_element (options, state, fname, FALSE); + } + contents_csum_v = NULL; /* iter_loop freed it */ + } + + /* Process subdirectories */ + { g_autoptr(GVariant) dir_subdirs = g_variant_get_child_value (dirtree, 1); + const char *dname; + g_autoptr(GVariant) subdirtree_csum_v = NULL; + g_autoptr(GVariant) subdirmeta_csum_v = NULL; + GVariantIter viter; + g_variant_iter_init (&viter, dir_subdirs); + while (g_variant_iter_loop (&viter, "(&s@ay@ay)", &dname, + &subdirtree_csum_v, &subdirmeta_csum_v)) + { + /* Validate this up front to prevent path traversal attacks. Note that + * we don't validate at the top of this function like we do for + * checkout_one_file_at() becuase I believe in some cases this function + * can be called *initially* with user-specified paths for the root + * directory. + */ + if (!ot_util_filename_validate (dname, error)) + return FALSE; + + push_path_element (options, state, dname, TRUE); + + char subdirtree_checksum[OSTREE_SHA256_STRING_LEN+1]; + _ostree_checksum_inplace_from_bytes_v (subdirtree_csum_v, subdirtree_checksum); + char subdirmeta_checksum[OSTREE_SHA256_STRING_LEN+1]; + _ostree_checksum_inplace_from_bytes_v (subdirmeta_csum_v, subdirmeta_checksum); + if (!checkout_tree_at_recurse (self, options, state, + destination_dfd, dname, + subdirtree_checksum, subdirmeta_checksum, + cancellable, error)) + return FALSE; + + pop_path_element (options, state, dname, TRUE); + } + } + + /* We do fchmod/fchown last so that no one else could access the + * partially created directory and change content we're laying out. + */ + if (!did_exist) + { + guint32 canonical_mode; + /* Silently ignore world-writable directories (plus sticky, suid bits, + * etc.) when doing a checkout for bare-user-only repos, or if requested explicitly. + * This is related to the logic in ostree-repo-commit.c for files. + * See also: https://github.com/ostreedev/ostree/pull/909 i.e. 0c4b3a2b6da950fd78e63f9afec602f6188f1ab0 + */ + if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY || options->bareuseronly_dirs) + canonical_mode = (mode & 0775) | S_IFDIR; + else + canonical_mode = mode; + if (TEMP_FAILURE_RETRY (fchmod (destination_dfd, canonical_mode)) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + } + + if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) + { + if (TEMP_FAILURE_RETRY (fchown (destination_dfd, uid, gid)) < 0) + return glnx_throw_errno (error); + } + + /* Set directory mtime to OSTREE_TIMESTAMP, so that it is constant for all checkouts. + * Must be done after setting permissions and creating all children. Note we skip doing + * this for directories that already exist (under the theory we possibly don't own them), + * and we also skip it if doing copying checkouts, which is mostly for /etc. + */ + if (!did_exist && !options->force_copy) + { + const struct timespec times[2] = { { OSTREE_TIMESTAMP, UTIME_OMIT }, { OSTREE_TIMESTAMP, 0} }; + if (TEMP_FAILURE_RETRY (futimens (destination_dfd, times)) < 0) + return glnx_throw_errno (error); + } + + if (fsync_is_enabled (self, options)) + { + if (fsync (destination_dfd) == -1) + return glnx_throw_errno (error); + } + + return TRUE; +} + +/* Begin a checkout process */ +static gboolean +checkout_tree_at (OstreeRepo *self, + OstreeRepoCheckoutAtOptions *options, + int destination_parent_fd, + const char *destination_name, + OstreeRepoFile *source, + GFileInfo *source_info, + GCancellable *cancellable, + GError **error) +{ + g_auto(CheckoutState) state = { 0, }; + + if (options->filter) + state.path_buf = g_string_new ("/"); + + /* If SELinux labeling is enabled, we need to keep track of the full path string */ + if (options->sepolicy) + { + /* Otherwise it'd just be corrupting things, and there's no use case */ + g_assert (options->force_copy); + + const char *prefix = options->sepolicy_prefix ?: options->subpath; + if (g_str_equal (prefix, "/") && state.path_buf) + { + /* just use the same scratchpad if we can */ + state.selabel_path_buf = state.path_buf; + } + else + { + GString *buf = g_string_new (prefix); + g_assert_cmpint (buf->len, >, 0); + /* Ensure it ends with / */ + if (buf->str[buf->len-1] != '/') + g_string_append_c (buf, '/'); + state.selabel_path_buf = buf; + } + } + + /* Uncompressed archive caches; should be considered deprecated */ + const gboolean can_cache = (options->enable_uncompressed_cache + && self->enable_uncompressed_cache); + if (can_cache + && !_ostree_repo_mode_is_bare (self->mode) + && self->uncompressed_objects_dir_fd < 0) + { + self->uncompressed_objects_dir_fd = + glnx_opendirat_with_errno (self->repo_dir_fd, "uncompressed-objects-cache", TRUE); + if (self->uncompressed_objects_dir_fd < 0 && errno != ENOENT) + return glnx_throw_errno_prefix (error, "opendir(uncompressed-objects-cache)"); + } + + /* Special case handling for subpath of a non-directory */ + if (g_file_info_get_file_type (source_info) != G_FILE_TYPE_DIRECTORY) + { + /* For backwards compat reasons, we do a mkdir() here. However, as a + * special case to allow callers to directly check out files without an + * intermediate root directory, we will skip mkdirat() if + * `destination_name` == `.`, since obviously the current directory + * exists. + */ + int destination_dfd = destination_parent_fd; + glnx_autofd int destination_dfd_owned = -1; + if (!g_str_equal (destination_name, ".")) + { + if (mkdirat (destination_parent_fd, destination_name, 0700) < 0 + && errno != EEXIST) + return glnx_throw_errno_prefix (error, "mkdirat"); + if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE, + &destination_dfd_owned, error)) + return FALSE; + destination_dfd = destination_dfd_owned; + } + /* let's just ignore filter here; I can't think of a useful case for filtering when + * only checking out one path */ + options->filter = NULL; + return checkout_one_file_at (self, options, &state, + ostree_repo_file_get_checksum (source), + destination_dfd, + g_file_info_get_name (source_info), + cancellable, error); + } + + /* Cache any directory metadata we read during this operation; + * see commit b7afe91e21143d7abb0adde440683a52712aa246 + */ + g_auto(OstreeRepoMemoryCacheRef) memcache_ref; + _ostree_repo_memory_cache_ref_init (&memcache_ref, self); + + g_assert_cmpint (g_file_info_get_file_type (source_info), ==, G_FILE_TYPE_DIRECTORY); + const char *dirtree_checksum = ostree_repo_file_tree_get_contents_checksum (source); + const char *dirmeta_checksum = ostree_repo_file_tree_get_metadata_checksum (source); + return checkout_tree_at_recurse (self, options, &state, destination_parent_fd, + destination_name, + dirtree_checksum, dirmeta_checksum, + cancellable, error); +} + +static void +canonicalize_options (OstreeRepo *self, + OstreeRepoCheckoutAtOptions *options) +{ + /* Canonicalize subpath to / */ + if (!options->subpath) + options->subpath = "/"; + + /* Force USER mode for BARE_USER_ONLY always - nothing else makes sense */ + if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY) + options->mode = OSTREE_REPO_CHECKOUT_MODE_USER; +} + +/** + * ostree_repo_checkout_tree: + * @self: Repo + * @mode: Options controlling all files + * @overwrite_mode: Whether or not to overwrite files + * @destination: Place tree here + * @source: Source tree + * @source_info: Source info + * @cancellable: Cancellable + * @error: Error + * + * Check out @source into @destination, which must live on the + * physical filesystem. @source may be any subdirectory of a given + * commit. The @mode and @overwrite_mode allow control over how the + * files are checked out. + */ +gboolean +ostree_repo_checkout_tree (OstreeRepo *self, + OstreeRepoCheckoutMode mode, + OstreeRepoCheckoutOverwriteMode overwrite_mode, + GFile *destination, + OstreeRepoFile *source, + GFileInfo *source_info, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoCheckoutAtOptions options = { 0, }; + options.mode = mode; + options.overwrite_mode = overwrite_mode; + /* Backwards compatibility */ + options.enable_uncompressed_cache = TRUE; + canonicalize_options (self, &options); + + return checkout_tree_at (self, &options, + AT_FDCWD, gs_file_get_path_cached (destination), + source, source_info, + cancellable, error); +} + +/** + * ostree_repo_checkout_tree_at: (skip) + * @self: Repo + * @options: (allow-none): Options + * @destination_dfd: Directory FD for destination + * @destination_path: Directory for destination + * @commit: Checksum for commit + * @cancellable: Cancellable + * @error: Error + * + * Similar to ostree_repo_checkout_tree(), but uses directory-relative + * paths for the destination, uses a new `OstreeRepoCheckoutAtOptions`, + * and takes a commit checksum and optional subpath pair, rather than + * requiring use of `GFile` APIs for the caller. + * + * Note in addition that unlike ostree_repo_checkout_tree(), the + * default is not to use the repository-internal uncompressed objects + * cache. + * + * This function is deprecated. Use ostree_repo_checkout_at() instead. + */ +gboolean +ostree_repo_checkout_tree_at (OstreeRepo *self, + OstreeRepoCheckoutOptions *options, + int destination_dfd, + const char *destination_path, + const char *commit, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoCheckoutAtOptions new_opts = {0, }; + new_opts.mode = options->mode; + new_opts.overwrite_mode = options->overwrite_mode; + new_opts.enable_uncompressed_cache = options->enable_uncompressed_cache; + new_opts.enable_fsync = options->disable_fsync ? FALSE : self->disable_fsync; + new_opts.process_whiteouts = options->process_whiteouts; + new_opts.no_copy_fallback = options->no_copy_fallback; + new_opts.subpath = options->subpath; + new_opts.devino_to_csum_cache = options->devino_to_csum_cache; + return ostree_repo_checkout_at (self, &new_opts, destination_dfd, + destination_path, commit, cancellable, error); +} + +/** + * ostree_repo_checkout_at: + * @self: Repo + * @options: (allow-none): Options + * @destination_dfd: Directory FD for destination + * @destination_path: Directory for destination + * @commit: Checksum for commit + * @cancellable: Cancellable + * @error: Error + * + * Similar to ostree_repo_checkout_tree(), but uses directory-relative + * paths for the destination, uses a new `OstreeRepoCheckoutAtOptions`, + * and takes a commit checksum and optional subpath pair, rather than + * requiring use of `GFile` APIs for the caller. + * + * It also replaces ostree_repo_checkout_at() which was not safe to + * use with GObject introspection. + * + * Note in addition that unlike ostree_repo_checkout_tree(), the + * default is not to use the repository-internal uncompressed objects + * cache. + * + * Since: 2016.8 + */ +gboolean +ostree_repo_checkout_at (OstreeRepo *self, + OstreeRepoCheckoutAtOptions *options, + int destination_dfd, + const char *destination_path, + const char *commit, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoCheckoutAtOptions default_options = { 0, }; + OstreeRepoCheckoutAtOptions real_options; + + if (!options) + { + default_options.subpath = NULL; + options = &default_options; + } + + /* Make a copy so we can modify the options */ + real_options = *options; + options = &real_options; + canonicalize_options (self, options); + + g_return_val_if_fail (!(options->force_copy && options->no_copy_fallback), FALSE); + g_return_val_if_fail (!options->sepolicy || options->force_copy, FALSE); + /* union identical requires hardlink mode */ + g_return_val_if_fail (!(options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL && + !options->no_copy_fallback), FALSE); + + g_autoptr(GFile) commit_root = (GFile*) _ostree_repo_file_new_for_commit (self, commit, error); + if (!commit_root) + return FALSE; + + if (!ostree_repo_file_ensure_resolved ((OstreeRepoFile*)commit_root, error)) + return FALSE; + + g_autoptr(GFile) target_dir = NULL; + + if (strcmp (options->subpath, "/") != 0) + target_dir = g_file_get_child (commit_root, options->subpath); + else + target_dir = g_object_ref (commit_root); + g_autoptr(GFileInfo) target_info = + g_file_query_info (target_dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!target_info) + return FALSE; + + if (!checkout_tree_at (self, options, + destination_dfd, + destination_path, + (OstreeRepoFile*)target_dir, target_info, + cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_repo_checkout_at_options_set_devino: + * @opts: Checkout options + * @cache: (transfer none) (nullable): Devino cache + * + * This function simply assigns @cache to the `devino_to_csum_cache` member of + * @opts; it's only useful for introspection. + * + * Note that cache does *not* have its refcount incremented - the lifetime of + * @cache must be equal to or greater than that of @opts. + * + * Since: 2017.13 + */ +void +ostree_repo_checkout_at_options_set_devino (OstreeRepoCheckoutAtOptions *opts, + OstreeRepoDevInoCache *cache) +{ + opts->devino_to_csum_cache = cache; +} + +static guint +devino_hash (gconstpointer a) +{ + OstreeDevIno *a_i = (gpointer)a; + return (guint) (a_i->dev + a_i->ino); +} + +static int +devino_equal (gconstpointer a, + gconstpointer b) +{ + OstreeDevIno *a_i = (gpointer)a; + OstreeDevIno *b_i = (gpointer)b; + return a_i->dev == b_i->dev + && a_i->ino == b_i->ino; +} + +/** + * ostree_repo_devino_cache_new: + * + * OSTree has support for pairing ostree_repo_checkout_tree_at() using + * hardlinks in combination with a later + * ostree_repo_write_directory_to_mtree() using a (normally modified) + * directory. In order for OSTree to optimally detect just the new + * files, use this function and fill in the `devino_to_csum_cache` + * member of `OstreeRepoCheckoutAtOptions`, then call + * ostree_repo_commit_set_devino_cache(). + * + * Returns: (transfer full): Newly allocated cache + */ +OstreeRepoDevInoCache * +ostree_repo_devino_cache_new (void) +{ + return (OstreeRepoDevInoCache*) g_hash_table_new_full (devino_hash, devino_equal, g_free, NULL); +} + +/** + * ostree_repo_checkout_gc: + * @self: Repo + * @cancellable: Cancellable + * @error: Error + * + * Call this after finishing a succession of checkout operations; it + * will delete any currently-unused uncompressed objects from the + * cache. + */ +gboolean +ostree_repo_checkout_gc (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GHashTable) to_clean_dirs = NULL; + + g_mutex_lock (&self->cache_lock); + to_clean_dirs = self->updated_uncompressed_dirs; + self->updated_uncompressed_dirs = g_hash_table_new (NULL, NULL); + g_mutex_unlock (&self->cache_lock); + + if (!to_clean_dirs) + return TRUE; /* Note early return */ + + GLNX_HASH_TABLE_FOREACH (to_clean_dirs, gpointer, prefix) + { + g_autofree char *objdir_name = g_strdup_printf ("%02x", GPOINTER_TO_UINT (prefix)); + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + + if (!glnx_dirfd_iterator_init_at (self->uncompressed_objects_dir_fd, objdir_name, FALSE, + &dfd_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent; + struct stat stbuf; + + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) != 0) + { + glnx_set_error_from_errno (error); + return FALSE; + } + + if (stbuf.st_nlink == 1) + { + if (!glnx_unlinkat (dfd_iter.fd, dent->d_name, 0, error)) + return FALSE; + } + } + } + + return TRUE; +} diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c new file mode 100644 index 0000000..0c9de23 --- /dev/null +++ b/src/libostree/ostree-repo-commit.c @@ -0,0 +1,4831 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LINUX_FSVERITY_H +#include +#endif + +#include "otutil.h" +#include "ostree.h" +#include "ostree-core-private.h" +#include "ostree-repo-private.h" +#include "ostree-sepolicy-private.h" +#include "ostree-repo-file-enumerator.h" +#include "ostree-checksum-input-stream.h" +#include "ostree-varint.h" + +/* The standardized version of BTRFS_IOC_CLONE */ +#ifndef FICLONE +#define FICLONE _IOW(0x94, 9, int) +#endif + +/* Understanding ostree's fsync strategy + * + * A long time ago, ostree used to invoke fsync() on each object, + * then move it into the objects directory. However, it turned + * out to be a *lot* faster to write the objects into a separate "staging" + * directory (letting the filesystem handle writeback how it likes) + * and then only walk over each of the files, fsync(), then rename() + * into place. See also https://lwn.net/Articles/789024/ + * + * (We also support a "disable fsync entirely" mode, where you don't + * care about integrity; e.g. test suites using disposable VMs). + * + * This "delayed fsync" pattern though is much worse for other concurrent processes + * like databases because it forces a lot to go through the filesystem + * journal at once once we do the sync. So now we support a `per_object_fsync` + * option that again invokes `fsync()` directly. This also notably + * provides "backpressure", ensuring we aren't queuing up a huge amount + * of I/O at once. + */ + +/* The directory where we place content */ +static int +commit_dest_dfd (OstreeRepo *self) +{ + if (self->per_object_fsync) + return self->objects_dir_fd; + else if (self->in_transaction && !self->disable_fsync) + return self->commit_stagedir.fd; + else + return self->objects_dir_fd; +} + +/* If we don't have O_TMPFILE, or for symlinks we'll create temporary + * files. If we have a txn, use the staging dir to ensure that + * things are consistently locked against concurrent cleanup, and + * in general we have all of our data in one place. + */ +static int +commit_tmp_dfd (OstreeRepo *self) +{ + if (self->in_transaction) + return self->commit_stagedir.fd; + else + return self->tmp_dir_fd; +} + +/* The objects/ directory has a two-character directory prefix for checksums + * to avoid putting lots of files in a single directory. This technique + * is quite old, but Git also uses it for example. + */ +gboolean +_ostree_repo_ensure_loose_objdir_at (int dfd, + const char *loose_path, + GCancellable *cancellable, + GError **error) +{ + char loose_prefix[3]; + + loose_prefix[0] = loose_path[0]; + loose_prefix[1] = loose_path[1]; + loose_prefix[2] = '\0'; + if (mkdirat (dfd, loose_prefix, 0777) == -1) + { + if (G_UNLIKELY (errno != EEXIST)) + { + glnx_set_error_from_errno (error); + return FALSE; + } + } + return TRUE; +} + +/* This GVariant is the header for content objects (regfiles and symlinks) */ +static GVariant * +create_file_metadata (guint32 uid, + guint32 gid, + guint32 mode, + GVariant *xattrs) +{ + GVariant *ret_metadata = NULL; + g_autoptr(GVariant) tmp_xattrs = NULL; + + if (xattrs == NULL) + tmp_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); + + ret_metadata = g_variant_new ("(uuu@a(ayay))", + GUINT32_TO_BE (uid), + GUINT32_TO_BE (gid), + GUINT32_TO_BE (mode), + xattrs ? xattrs : tmp_xattrs); + g_variant_ref_sink (ret_metadata); + + return ret_metadata; +} + +/* bare-user repositories store file metadata as a user xattr */ +gboolean +_ostree_write_bareuser_metadata (int fd, + guint32 uid, + guint32 gid, + guint32 mode, + GVariant *xattrs, + GError **error) +{ + g_autoptr(GVariant) filemeta = create_file_metadata (uid, gid, mode, xattrs); + + if (TEMP_FAILURE_RETRY (fsetxattr (fd, "user.ostreemeta", + (char*)g_variant_get_data (filemeta), + g_variant_get_size (filemeta), + 0)) != 0) + return glnx_throw_errno_prefix (error, "fsetxattr(user.ostreemeta)"); + + return TRUE; +} + +/* See https://github.com/ostreedev/ostree/pull/698 */ +#ifdef WITH_SMACK +#define XATTR_NAME_SMACK "security.SMACK64" +#endif + +static void +ot_security_smack_reset_dfd_name (int dfd, const char *name) +{ +#ifdef WITH_SMACK + char buf[PATH_MAX]; + /* See glnx-xattrs.c */ + snprintf (buf, sizeof (buf), "/proc/self/fd/%d/%s", dfd, name); + (void) lremovexattr (buf, XATTR_NAME_SMACK); +#endif +} + +static void +ot_security_smack_reset_fd (int fd) +{ +#ifdef WITH_SMACK + (void) fremovexattr (fd, XATTR_NAME_SMACK); +#endif +} + +/* Wrapper around the fsverity ioctl, compressing the result to + * "success, unsupported or error". This is used for /boot where + * we enable verity if supported. + * */ +gboolean +_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf, + _OstreeFeatureSupport fsverity_requested, + gboolean *supported, + GError **error) +{ + /* Set this by default to simplify the code below */ + if (supported) + *supported = FALSE; + + if (fsverity_requested == _OSTREE_FEATURE_NO) + return TRUE; + +#ifdef HAVE_LINUX_FSVERITY_H + GLNX_AUTO_PREFIX_ERROR ("fsverity", error); + + /* fs-verity requires a read-only file descriptor */ + if (!glnx_tmpfile_reopen_rdonly (tmpf, error)) + return FALSE; + + struct fsverity_enable_arg arg = { 0, }; + arg.version = 1; + arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; /* TODO configurable? */ + arg.block_size = 4096; /* FIXME query */ + arg.salt_size = 0; /* TODO store salt in ostree repo config */ + arg.salt_ptr = 0; + arg.sig_size = 0; /* We don't currently expect use of in-kernel signature verification */ + arg.sig_ptr = 0; + + if (ioctl (tmpf->fd, FS_IOC_ENABLE_VERITY, &arg) < 0) + { + switch (errno) + { + case ENOTTY: + case EOPNOTSUPP: + return TRUE; + default: + return glnx_throw_errno_prefix (error, "ioctl(FS_IOC_ENABLE_VERITY)"); + } + } + + if (supported) + *supported = TRUE; +#endif + return TRUE; +} + +/* Enable verity on a file, respecting the "wanted" and "supported" states. + * The main idea here is to optimize out pointlessly calling the ioctl() + * over and over in cases where it's not supported for the repo's filesystem, + * as well as to support "opportunistic" use (requested and if filesystem supports). + * */ +gboolean +_ostree_tmpf_fsverity (OstreeRepo *self, + GLnxTmpfile *tmpf, + GError **error) +{ +#ifdef HAVE_LINUX_FSVERITY_H + g_mutex_lock (&self->txn_lock); + _OstreeFeatureSupport fsverity_wanted = self->fs_verity_wanted; + _OstreeFeatureSupport fsverity_supported = self->fs_verity_supported; + g_mutex_unlock (&self->txn_lock); + + switch (fsverity_wanted) + { + case _OSTREE_FEATURE_YES: + { + if (fsverity_supported == _OSTREE_FEATURE_NO) + return glnx_throw (error, "fsverity required but filesystem does not support it"); + } + break; + case _OSTREE_FEATURE_MAYBE: + break; + case _OSTREE_FEATURE_NO: + return TRUE; + } + + gboolean supported = FALSE; + if (!_ostree_tmpf_fsverity_core (tmpf, fsverity_wanted, &supported, error)) + return FALSE; + + if (!supported) + { + if (G_UNLIKELY (fsverity_wanted == _OSTREE_FEATURE_YES)) + return glnx_throw (error, "fsverity required but filesystem does not support it"); + + /* If we got here, we must be trying "opportunistic" use of fs-verity */ + g_assert_cmpint (fsverity_wanted, ==, _OSTREE_FEATURE_MAYBE); + g_mutex_lock (&self->txn_lock); + self->fs_verity_supported = _OSTREE_FEATURE_NO; + g_mutex_unlock (&self->txn_lock); + return TRUE; + } + + g_mutex_lock (&self->txn_lock); + self->fs_verity_supported = _OSTREE_FEATURE_YES; + g_mutex_unlock (&self->txn_lock); +#else + g_assert_cmpint (self->fs_verity_wanted, !=, _OSTREE_FEATURE_YES); +#endif + return TRUE; +} + +/* Given an O_TMPFILE regular file, link it into place. */ +gboolean +_ostree_repo_commit_tmpf_final (OstreeRepo *self, + const char *checksum, + OstreeObjectType objtype, + GLnxTmpfile *tmpf, + GCancellable *cancellable, + GError **error) +{ + char tmpbuf[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (tmpbuf, checksum, objtype, self->mode); + + int dest_dfd = commit_dest_dfd (self); + if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, tmpbuf, + cancellable, error)) + return FALSE; + + if (!_ostree_tmpf_fsverity (self, tmpf, error)) + return FALSE; + + if (!glnx_link_tmpfile_at (tmpf, GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST, + dest_dfd, tmpbuf, error)) + return FALSE; + /* We're done with the fd */ + glnx_tmpfile_clear (tmpf); + return TRUE; +} + +/* Given a dfd+path combination (may be regular file or symlink), + * rename it into place. + */ +static gboolean +commit_path_final (OstreeRepo *self, + const char *checksum, + OstreeObjectType objtype, + OtCleanupUnlinkat *tmp_path, + GCancellable *cancellable, + GError **error) +{ + /* The final renameat() */ + char tmpbuf[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (tmpbuf, checksum, objtype, self->mode); + + int dest_dfd = commit_dest_dfd (self); + if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, tmpbuf, + cancellable, error)) + return FALSE; + + if (renameat (tmp_path->dfd, tmp_path->path, + dest_dfd, tmpbuf) == -1) + { + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "Storing file '%s'", tmp_path->path); + /* Otherwise, the caller's cleanup will unlink+free */ + } + else + { + /* The tmp path was consumed */ + ot_cleanup_unlinkat_clear (tmp_path); + } + + return TRUE; +} + + +/* Given either a file or symlink, apply the final metadata to it depending on + * the repository mode. Note that @checksum is assumed to have been validated by + * the caller. + */ +static gboolean +commit_loose_regfile_object (OstreeRepo *self, + const char *checksum, + GLnxTmpfile *tmpf, + guint32 uid, + guint32 gid, + guint32 mode, + GVariant *xattrs, + GCancellable *cancellable, + GError **error) +{ + if (self->mode == OSTREE_REPO_MODE_BARE) + { + if (TEMP_FAILURE_RETRY (fchown (tmpf->fd, uid, gid)) < 0) + return glnx_throw_errno_prefix (error, "fchown"); + + if (TEMP_FAILURE_RETRY (fchmod (tmpf->fd, mode)) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + if (xattrs) + { + ot_security_smack_reset_fd (tmpf->fd); + if (!glnx_fd_set_all_xattrs (tmpf->fd, xattrs, cancellable, error)) + return FALSE; + } + } + else if (self->mode == OSTREE_REPO_MODE_BARE_USER) + { + if (!_ostree_write_bareuser_metadata (tmpf->fd, uid, gid, mode, xattrs, error)) + return FALSE; + + /* Note that previously this path added `| 0755` which made every + * file executable, see + * https://github.com/ostreedev/ostree/issues/907 + * We then changed it to mask by 0775, but we always need at least read + * permission when running as non-root, so explicitly mask that in. + * + * Again here, symlinks in bare-user are a hairy special case; only do a + * chmod for a *real* regular file, otherwise we'll take the default 0644. + */ + if (S_ISREG (mode)) + { + const mode_t content_mode = (mode & (S_IFREG | 0775)) | S_IRUSR; + if (!glnx_fchmod (tmpf->fd, content_mode, error)) + return FALSE; + } + else + g_assert (S_ISLNK (mode)); + } + else if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) + { + if (!_ostree_validate_bareuseronly_mode (mode, checksum, error)) + return FALSE; + + if (!glnx_fchmod (tmpf->fd, mode, error)) + return FALSE; + } + + if (_ostree_repo_mode_is_bare (self->mode)) + { + /* To satisfy tools such as guile which compare mtimes + * to determine whether or not source files need to be compiled, + * set the modification time to OSTREE_TIMESTAMP. + */ + const struct timespec times[2] = { { OSTREE_TIMESTAMP, UTIME_OMIT }, { OSTREE_TIMESTAMP, 0} }; + if (TEMP_FAILURE_RETRY (futimens (tmpf->fd, times)) < 0) + return glnx_throw_errno_prefix (error, "futimens"); + } + + /* Ensure that in case of a power cut, these files have the data we + * want. See http://lwn.net/Articles/322823/ + */ + if (!self->disable_fsync && self->per_object_fsync) + { + if (fsync (tmpf->fd) == -1) + return glnx_throw_errno_prefix (error, "fsync"); + } + + if (!_ostree_repo_commit_tmpf_final (self, checksum, OSTREE_OBJECT_TYPE_FILE, + tmpf, cancellable, error)) + return FALSE; + + return TRUE; +} + +/* This is used by OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES */ +typedef struct +{ + OstreeObjectType objtype; + goffset unpacked; + goffset archived; +} OstreeContentSizeCacheEntry; + +static OstreeContentSizeCacheEntry * +content_size_cache_entry_new (OstreeObjectType objtype, + goffset unpacked, + goffset archived) +{ + OstreeContentSizeCacheEntry *entry = g_slice_new0 (OstreeContentSizeCacheEntry); + + entry->objtype = objtype; + entry->unpacked = unpacked; + entry->archived = archived; + + return entry; +} + +static void +content_size_cache_entry_free (gpointer entry) +{ + if (entry) + g_slice_free (OstreeContentSizeCacheEntry, entry); +} + +void +_ostree_repo_setup_generate_sizes (OstreeRepo *self, + OstreeRepoCommitModifier *modifier) +{ + if (modifier && modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES) + { + if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_ARCHIVE) + { + self->generate_sizes = TRUE; + + /* Clear any stale data in the object sizes hash table */ + if (self->object_sizes != NULL) + g_hash_table_remove_all (self->object_sizes); + } + else + g_debug ("Not generating sizes for non-archive repo"); + } +} + +static void +repo_ensure_size_entries (OstreeRepo *self) +{ + if (G_UNLIKELY (self->object_sizes == NULL)) + self->object_sizes = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, content_size_cache_entry_free); +} + +static gboolean +repo_has_size_entry (OstreeRepo *self, + OstreeObjectType objtype, + const gchar *checksum) +{ + /* Only file, dirtree and dirmeta objects appropriate for size metadata */ + if (objtype > OSTREE_OBJECT_TYPE_DIR_META) + return TRUE; + + repo_ensure_size_entries (self); + return (g_hash_table_lookup (self->object_sizes, checksum) != NULL); +} + +static void +repo_store_size_entry (OstreeRepo *self, + OstreeObjectType objtype, + const gchar *checksum, + goffset unpacked, + goffset archived) +{ + /* Only file, dirtree and dirmeta objects appropriate for size metadata */ + if (objtype > OSTREE_OBJECT_TYPE_DIR_META) + return; + + repo_ensure_size_entries (self); + g_hash_table_replace (self->object_sizes, + g_strdup (checksum), + content_size_cache_entry_new (objtype, unpacked, archived)); +} + +static int +compare_ascii_checksums_for_sorting (gconstpointer a_pp, + gconstpointer b_pp) +{ + char *a = *((char**)a_pp); + char *b = *((char**)b_pp); + + return strcmp (a, b); +} + +/* + * Create sizes metadata GVariant and add it to the metadata variant given. + */ +static GVariant * +add_size_index_to_metadata (OstreeRepo *self, + GVariant *original_metadata) +{ + g_autoptr(GVariantBuilder) builder = NULL; + + /* original_metadata may be NULL */ + builder = ot_util_variant_builder_from_variant (original_metadata, G_VARIANT_TYPE ("a{sv}")); + + if (self->object_sizes && + g_hash_table_size (self->object_sizes) > 0) + { + GVariantBuilder index_builder; + g_variant_builder_init (&index_builder, + G_VARIANT_TYPE ("a" _OSTREE_OBJECT_SIZES_ENTRY_SIGNATURE)); + + /* Sort the checksums so we can bsearch if desired */ + g_autoptr(GPtrArray) sorted_keys = g_ptr_array_new (); + GLNX_HASH_TABLE_FOREACH (self->object_sizes, const char*, e_checksum) + g_ptr_array_add (sorted_keys, (gpointer)e_checksum); + g_ptr_array_sort (sorted_keys, compare_ascii_checksums_for_sorting); + + for (guint i = 0; i < sorted_keys->len; i++) + { + guint8 csum[OSTREE_SHA256_DIGEST_LEN]; + const char *e_checksum = sorted_keys->pdata[i]; + g_autoptr(GString) buffer = g_string_new (NULL); + + ostree_checksum_inplace_to_bytes (e_checksum, csum); + g_string_append_len (buffer, (char*)csum, sizeof (csum)); + + OstreeContentSizeCacheEntry *e_size = + g_hash_table_lookup (self->object_sizes, e_checksum); + _ostree_write_varuint64 (buffer, e_size->archived); + _ostree_write_varuint64 (buffer, e_size->unpacked); + g_string_append_c (buffer, (gchar) e_size->objtype); + + g_variant_builder_add (&index_builder, "@ay", + ot_gvariant_new_bytearray ((guint8*)buffer->str, buffer->len)); + } + + g_variant_builder_add (builder, "{sv}", "ostree.sizes", + g_variant_builder_end (&index_builder)); + + /* Clear the object sizes hash table for a subsequent commit. */ + g_hash_table_remove_all (self->object_sizes); + } + + return g_variant_ref_sink (g_variant_builder_end (builder)); +} + +static gboolean +throw_min_free_space_error (OstreeRepo *self, + guint64 bytes_required, + GError **error) +{ + const char *err_msg = NULL; + g_autofree char *err_msg_owned = NULL; + + if (bytes_required > 0) + { + g_autofree char *formatted_required = g_format_size (bytes_required); + err_msg = err_msg_owned = g_strdup_printf ("would be exceeded, at least %s requested", formatted_required); + } + else + err_msg = "would be exceeded"; + + if (self->min_free_space_mb > 0) + return glnx_throw (error, "min-free-space-size %" G_GUINT64_FORMAT "MB %s", self->min_free_space_mb, err_msg); + else + return glnx_throw (error, "min-free-space-percent '%u%%' %s", self->min_free_space_percent, err_msg); +} + +typedef struct { + gboolean initialized; + GLnxTmpfile tmpf; + char *expected_checksum; + OtChecksum checksum; + guint64 content_len; + guint64 bytes_written; + guint uid; + guint gid; + guint mode; + GVariant *xattrs; +} OstreeRealRepoBareContent; +G_STATIC_ASSERT (sizeof (OstreeRepoBareContent) >= sizeof (OstreeRealRepoBareContent)); + +/* Create a tmpfile for writing a bare file. Currently just used + * by the static delta code, but will likely later be extended + * to be used also by the dfd_iter commit path. + */ +gboolean +_ostree_repo_bare_content_open (OstreeRepo *self, + const char *expected_checksum, + guint64 content_len, + guint uid, + guint gid, + guint mode, + GVariant *xattrs, + OstreeRepoBareContent *out_regwrite, + GCancellable *cancellable, + GError **error) +{ + OstreeRealRepoBareContent *real = (OstreeRealRepoBareContent*) out_regwrite; + g_assert (!real->initialized); + real->initialized = TRUE; + g_assert (S_ISREG (mode)); + if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", O_WRONLY|O_CLOEXEC, + &real->tmpf, error)) + return FALSE; + ot_checksum_init (&real->checksum); + real->expected_checksum = g_strdup (expected_checksum); + real->content_len = content_len; + real->bytes_written = 0; + real->uid = uid; + real->gid = gid; + real->mode = mode; + real->xattrs = xattrs ? g_variant_ref (xattrs) : NULL; + + /* Initialize the checksum with the header info */ + g_autoptr(GFileInfo) finfo = _ostree_mode_uidgid_to_gfileinfo (mode, uid, gid); + g_autoptr(GBytes) header = _ostree_file_header_new (finfo, xattrs); + ot_checksum_update_bytes (&real->checksum, header); + + return TRUE; +} + +gboolean +_ostree_repo_bare_content_write (OstreeRepo *repo, + OstreeRepoBareContent *barewrite, + const guint8 *buf, + size_t len, + GCancellable *cancellable, + GError **error) +{ + OstreeRealRepoBareContent *real = (OstreeRealRepoBareContent*) barewrite; + g_assert (real->initialized); + ot_checksum_update (&real->checksum, buf, len); + if (glnx_loop_write (real->tmpf.fd, buf, len) < 0) + return glnx_throw_errno_prefix (error, "write"); + return TRUE; +} + +gboolean +_ostree_repo_bare_content_commit (OstreeRepo *self, + OstreeRepoBareContent *barewrite, + char *checksum_buf, + size_t buflen, + GCancellable *cancellable, + GError **error) +{ + OstreeRealRepoBareContent *real = (OstreeRealRepoBareContent*) barewrite; + g_assert (real->initialized); + + if ((self->min_free_space_percent > 0 || self->min_free_space_mb > 0) && self->in_transaction) + { + struct stat st_buf; + if (!glnx_fstat (real->tmpf.fd, &st_buf, error)) + return FALSE; + + g_mutex_lock (&self->txn_lock); + g_assert_cmpint (self->txn.blocksize, >, 0); + + const fsblkcnt_t object_blocks = (st_buf.st_size / self->txn.blocksize) + 1; + if (object_blocks > self->txn.max_blocks) + { + self->cleanup_stagedir = TRUE; + g_mutex_unlock (&self->txn_lock); + return throw_min_free_space_error (self, st_buf.st_size, error); + } + /* This is the main bit that needs mutex protection */ + self->txn.max_blocks -= object_blocks; + g_mutex_unlock (&self->txn_lock); + } + + ot_checksum_get_hexdigest (&real->checksum, checksum_buf, buflen); + + if (real->expected_checksum && + !_ostree_compare_object_checksum (OSTREE_OBJECT_TYPE_FILE, + real->expected_checksum, checksum_buf, + error)) + return FALSE; + + if (!commit_loose_regfile_object (self, checksum_buf, + &real->tmpf, real->uid, real->gid, + real->mode, real->xattrs, + cancellable, error)) + return FALSE; + + /* Let's have a guarantee that after commit the object is cleaned up */ + _ostree_repo_bare_content_cleanup (barewrite); + return TRUE; +} + +void +_ostree_repo_bare_content_cleanup (OstreeRepoBareContent *regwrite) +{ + OstreeRealRepoBareContent *real = (OstreeRealRepoBareContent*) regwrite; + if (!real->initialized) + return; + glnx_tmpfile_clear (&real->tmpf); + ot_checksum_clear (&real->checksum); + g_clear_pointer (&real->expected_checksum, (GDestroyNotify)g_free); + g_clear_pointer (&real->xattrs, (GDestroyNotify)g_variant_unref); + real->initialized = FALSE; +} + +/* Allocate an O_TMPFILE, write everything from @input to it, but + * not exceeding @length. Used for every object in archive repos, + * and content objects in all bare-type repos. + */ +static gboolean +create_regular_tmpfile_linkable_with_content (OstreeRepo *self, + guint64 length, + GInputStream *input, + GLnxTmpfile *out_tmpf, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", O_WRONLY|O_CLOEXEC, + &tmpf, error)) + return FALSE; + + if (!glnx_try_fallocate (tmpf.fd, 0, length, error)) + return FALSE; + + if (G_IS_FILE_DESCRIPTOR_BASED (input)) + { + int infd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*) input); + if (glnx_regfile_copy_bytes (infd, tmpf.fd, (off_t)length) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); + } + else + { + /* We used to do a g_output_stream_splice(), but there are two issues with that: + * - We want to honor the size provided, to avoid malicious content that says it's + * e.g. 10 bytes but is actually gigabytes. + * - Due to GLib bugs that pointlessly calls `poll()` on the output fd for every write + */ + char buf[8192]; + guint64 remaining = length; + while (remaining > 0) + { + const gssize bytes_read = + g_input_stream_read (input, buf, MIN (remaining, sizeof (buf)), cancellable, error); + if (bytes_read < 0) + return FALSE; + else if (bytes_read == 0) + return glnx_throw (error, "Unexpected EOF with %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " bytes remaining", remaining, length); + if (glnx_loop_write (tmpf.fd, buf, bytes_read) < 0) + return glnx_throw_errno_prefix (error, "write"); + remaining -= bytes_read; + } + } + + if (!glnx_fchmod (tmpf.fd, 0644, error)) + return FALSE; + + *out_tmpf = tmpf; tmpf.initialized = FALSE; + return TRUE; +} + +static gboolean +_check_support_reflink (OstreeRepo *dest, gboolean *supported, GError **error) +{ + /* We have not checked yet if the destination file system supports reflinks, do it here */ + if (g_atomic_int_get (&dest->fs_support_reflink) == 0) + { + glnx_autofd int src_fd = -1; + g_auto(GLnxTmpfile) dest_tmpf = { 0, }; + + if (!glnx_openat_rdonly (dest->repo_dir_fd, "config", TRUE, &src_fd, error)) + return FALSE; + if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (dest), ".", O_WRONLY|O_CLOEXEC, + &dest_tmpf, error)) + return FALSE; + + if (ioctl (dest_tmpf.fd, FICLONE, src_fd) == 0) + g_atomic_int_set (&dest->fs_support_reflink, 1); + else if (errno == EOPNOTSUPP) /* Ignore other kind of errors as they might be temporary failures */ + g_atomic_int_set (&dest->fs_support_reflink, -1); + } + *supported = g_atomic_int_get (&dest->fs_support_reflink) >= 0; + return TRUE; +} + +static gboolean +_create_payload_link (OstreeRepo *self, + const char *checksum, + const char *payload_checksum, + GFileInfo *file_info, + GCancellable *cancellable, + GError **error) +{ + gboolean reflinks_supported = FALSE; + + if (!_check_support_reflink (self, &reflinks_supported, error)) + return FALSE; + + if (!reflinks_supported) + return TRUE; + + if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR + || !G_IN_SET(self->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER_ONLY)) + return TRUE; + + if (payload_checksum == NULL || g_file_info_get_size (file_info) < self->payload_link_threshold) + return TRUE; + + char target_buf[_OSTREE_LOOSE_PATH_MAX + _OSTREE_PAYLOAD_LINK_PREFIX_LEN]; + strcpy (target_buf, _OSTREE_PAYLOAD_LINK_PREFIX); + _ostree_loose_path (target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN, checksum, OSTREE_OBJECT_TYPE_FILE, self->mode); + + if (symlinkat (target_buf, commit_tmp_dfd (self), payload_checksum) < 0) + { + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "symlinkat"); + } + else + { + g_auto(OtCleanupUnlinkat) tmp_unlinker = { commit_tmp_dfd (self), g_strdup (payload_checksum) }; + if (!commit_path_final (self, payload_checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, &tmp_unlinker, cancellable, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +_import_payload_link (OstreeRepo *dest_repo, + OstreeRepo *src_repo, + const char *checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean reflinks_supported = FALSE; + g_autofree char *payload_checksum = NULL; + g_autoptr(GInputStream) is = NULL; + glnx_unref_object OtChecksumInstream *checksum_payload = NULL; + g_autoptr(GFileInfo) file_info = NULL; + + /* The two repositories are on different devices */ + if (src_repo->device != dest_repo->device) + return TRUE; + + if (!_check_support_reflink (dest_repo, &reflinks_supported, error)) + return FALSE; + + if (!reflinks_supported) + return TRUE; + + if (!G_IN_SET(dest_repo->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER_ONLY)) + return TRUE; + + if (!ostree_repo_load_file (src_repo, checksum, &is, &file_info, NULL, cancellable, error)) + return FALSE; + + if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR + || g_file_info_get_size (file_info) < dest_repo->payload_link_threshold) + return TRUE; + + checksum_payload = ot_checksum_instream_new (is, G_CHECKSUM_SHA256); + + guint64 remaining = g_file_info_get_size (file_info); + while (remaining) + { + char buf[8192]; + gssize ret = g_input_stream_read ((GInputStream *) checksum_payload, buf, + MIN (sizeof (buf), remaining), cancellable, error); + if (ret < 0) + return FALSE; + remaining -= ret; + } + payload_checksum = ot_checksum_instream_get_string (checksum_payload); + + return _create_payload_link (dest_repo, checksum, payload_checksum, file_info, cancellable, error); +} + +static gboolean +_try_clone_from_payload_link (OstreeRepo *self, + OstreeRepo *dest_repo, + const char *payload_checksum, + GFileInfo *file_info, + GLnxTmpfile *tmpf, + GCancellable *cancellable, + GError **error) +{ + gboolean reflinks_supported = FALSE; + int dfd_searches[] = { -1, self->objects_dir_fd }; + if (self->commit_stagedir.initialized) + dfd_searches[0] = self->commit_stagedir.fd; + + /* The two repositories are on different devices */ + if (self->device != dest_repo->device) + return TRUE; + + if (!_check_support_reflink (dest_repo, &reflinks_supported, error)) + return FALSE; + + if (!reflinks_supported) + return TRUE; + + for (guint i = 0; i < G_N_ELEMENTS (dfd_searches); i++) + { + glnx_autofd int fdf = -1; + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + char loose_path_target_buf[_OSTREE_LOOSE_PATH_MAX]; + char target_buf[_OSTREE_LOOSE_PATH_MAX + _OSTREE_PAYLOAD_LINK_PREFIX_LEN]; + char target_checksum[OSTREE_SHA256_STRING_LEN+1]; + int dfd = dfd_searches[i]; + ssize_t size; + if (dfd == -1) + continue; + + _ostree_loose_path (loose_path_buf, payload_checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, self->mode); + + size = TEMP_FAILURE_RETRY (readlinkat (dfd, loose_path_buf, target_buf, sizeof (target_buf))); + if (size < 0) + { + if (errno == ENOENT) + continue; + return glnx_throw_errno_prefix (error, "readlinkat"); + } + + if (size < OSTREE_SHA256_STRING_LEN + _OSTREE_PAYLOAD_LINK_PREFIX_LEN) + return glnx_throw (error, "invalid data size for %s", loose_path_buf); + + sprintf (target_checksum, "%.2s%.62s", target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN, target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN + 3); + + _ostree_loose_path (loose_path_target_buf, target_checksum, OSTREE_OBJECT_TYPE_FILE, self->mode); + if (!ot_openat_ignore_enoent (dfd, loose_path_target_buf, &fdf, error)) + return FALSE; + + if (fdf < 0) + { + /* If the link is referring to an object that doesn't exist anymore in the repository, just unlink it. */ + if (!glnx_unlinkat (dfd, loose_path_buf, 0, error)) + return FALSE; + } + else + { + /* This undoes all of the previous writes; we want to generate reflinked data. */ + if (ftruncate (tmpf->fd, 0) < 0) + return glnx_throw_errno_prefix (error, "ftruncate"); + + if (glnx_regfile_copy_bytes (fdf, tmpf->fd, -1) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); + + return TRUE; + } + } + if (self->parent_repo) + return _try_clone_from_payload_link (self->parent_repo, dest_repo, payload_checksum, file_info, tmpf, cancellable, error); + + return TRUE; +} + +/* The main driver for writing a content (regfile or symlink) object. + * There are a variety of tricky cases here; for example, bare-user + * repos store symlinks as regular files. Computing checksums + * is optional; if @out_csum is `NULL`, we assume the caller already + * knows the checksum. + */ +static gboolean +write_content_object (OstreeRepo *self, + const char *expected_checksum, + GInputStream *input, + GFileInfo *file_info, + GVariant *xattrs, + guchar **out_csum, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Writing content object", error); + g_return_val_if_fail (expected_checksum || out_csum, FALSE); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + OstreeRepoMode repo_mode = ostree_repo_get_mode (self); + + GInputStream *file_input; /* Unowned alias */ + g_autoptr(GInputStream) file_input_owned = NULL; /* We need a temporary for bare-user symlinks */ + glnx_unref_object OtChecksumInstream *checksum_input = NULL; + glnx_unref_object OtChecksumInstream *checksum_payload_input = NULL; + const GFileType object_file_type = g_file_info_get_file_type (file_info); + if (out_csum) + { + /* Previously we checksummed the input verbatim; now + * ostree_repo_write_content() parses without checksumming, then we + * re-synthesize a header here. The data should be identical; if somehow + * it's not that's not a serious problem because we're still computing a + * checksum over the data we actually use. + */ + gboolean reflinks_supported = FALSE; + g_autoptr(GBytes) header = _ostree_file_header_new (file_info, xattrs); + size_t len; + const guint8 *buf = g_bytes_get_data (header, &len); + /* Give a null input if there's no content */ + g_autoptr(GInputStream) null_input = NULL; + if (!input) + { + null_input = input = g_memory_input_stream_new_from_data ("", 0, NULL); + (void) null_input; /* quiet static analysis */ + } + checksum_input = ot_checksum_instream_new_with_start (input, G_CHECKSUM_SHA256, + buf, len); + + if (!_check_support_reflink (self, &reflinks_supported, error)) + return FALSE; + + if (xattrs == NULL || !G_IN_SET(self->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER_ONLY) || object_file_type != G_FILE_TYPE_REGULAR || + !reflinks_supported) + file_input = (GInputStream*)checksum_input; + else + { + /* The payload checksum-input reads from the full object checksum-input; this + * means it skips the header. + */ + checksum_payload_input = ot_checksum_instream_new ((GInputStream*)checksum_input, G_CHECKSUM_SHA256); + file_input = (GInputStream*)checksum_payload_input; + } + } + else + file_input = input; + + gboolean phys_object_is_symlink = FALSE; + switch (object_file_type) + { + case G_FILE_TYPE_REGULAR: + break; + case G_FILE_TYPE_SYMBOLIC_LINK: + if (self->mode == OSTREE_REPO_MODE_BARE || self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) + phys_object_is_symlink = TRUE; + break; + default: + return glnx_throw (error, "Unsupported file type %u", object_file_type); + } + + guint64 size; + + /* For bare-user, convert the symlink target to the input stream */ + if (repo_mode == OSTREE_REPO_MODE_BARE_USER && object_file_type == G_FILE_TYPE_SYMBOLIC_LINK) + { + const char *target_str = g_file_info_get_symlink_target (file_info); + g_autoptr(GBytes) target = g_bytes_new (target_str, strlen (target_str) + 1); + + /* Include the terminating zero so we can e.g. mmap this file */ + file_input = file_input_owned = g_memory_input_stream_new_from_bytes (target); + size = g_bytes_get_size (target); + } + else if (!phys_object_is_symlink) + size = g_file_info_get_size (file_info); + else + size = 0; + + /* Free space check; only applies during transactions */ + if ((self->min_free_space_percent > 0 || self->min_free_space_mb > 0) && self->in_transaction) + { + g_mutex_lock (&self->txn_lock); + g_assert_cmpint (self->txn.blocksize, >, 0); + const fsblkcnt_t object_blocks = (size / self->txn.blocksize) + 1; + if (object_blocks > self->txn.max_blocks) + { + guint64 bytes_required = (guint64)object_blocks * self->txn.blocksize; + self->cleanup_stagedir = TRUE; + g_mutex_unlock (&self->txn_lock); + return throw_min_free_space_error (self, bytes_required, error); + } + /* This is the main bit that needs mutex protection */ + self->txn.max_blocks -= object_blocks; + g_mutex_unlock (&self->txn_lock); + } + + /* For regular files, we create them with default mode, and only + * later apply any xattrs and setuid bits. The rationale here + * is that an attacker on the network with the ability to MITM + * could potentially cause the system to make a temporary setuid + * binary with trailing garbage, creating a window on the local + * system where a malicious setuid binary exists. + * + * We use GLnxTmpfile for regular files, and OtCleanupUnlinkat for symlinks. + */ + g_auto(OtCleanupUnlinkat) tmp_unlinker = { commit_tmp_dfd (self), NULL }; + g_auto(GLnxTmpfile) tmpf = { 0, }; + goffset unpacked_size = 0; + /* Is it a symlink physically? */ + if (phys_object_is_symlink) + { + /* This will not be hit for bare-user or archive */ + g_assert (self->mode == OSTREE_REPO_MODE_BARE || self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY); + if (!_ostree_make_temporary_symlink_at (commit_tmp_dfd (self), + g_file_info_get_symlink_target (file_info), + &tmp_unlinker.path, + cancellable, error)) + return FALSE; + } + else if (repo_mode != OSTREE_REPO_MODE_ARCHIVE) + { + if (!create_regular_tmpfile_linkable_with_content (self, size, file_input, + &tmpf, cancellable, error)) + return FALSE; + } + else + { + g_autoptr(GConverter) zlib_compressor = NULL; + g_autoptr(GOutputStream) compressed_out_stream = NULL; + g_autoptr(GOutputStream) temp_out = NULL; + + g_assert (repo_mode == OSTREE_REPO_MODE_ARCHIVE); + + if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", O_WRONLY|O_CLOEXEC, + &tmpf, error)) + return FALSE; + temp_out = g_unix_output_stream_new (tmpf.fd, FALSE); + + g_autoptr(GBytes) file_meta_header = _ostree_zlib_file_header_new (file_info, xattrs); + gsize file_meta_len; + const guint8* file_meta_buf = g_bytes_get_data (file_meta_header, &file_meta_len); + + { gsize bytes_written; + if (!g_output_stream_write_all (temp_out, file_meta_buf, file_meta_len, &bytes_written, + cancellable, error)) + return FALSE; + } + + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) + { + zlib_compressor = (GConverter*)g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW, self->zlib_compression_level); + compressed_out_stream = g_converter_output_stream_new (temp_out, zlib_compressor); + /* Don't close the base; we'll do that later */ + g_filter_output_stream_set_close_base_stream ((GFilterOutputStream*)compressed_out_stream, FALSE); + + if (g_output_stream_splice (compressed_out_stream, file_input, + 0, cancellable, error) < 0) + return FALSE; + + unpacked_size = g_file_info_get_size (file_info); + } + else + { + /* For a symlink, the size is the length of the target */ + unpacked_size = strlen (g_file_info_get_symlink_target (file_info)); + } + + if (!g_output_stream_flush (temp_out, cancellable, error)) + return FALSE; + + if (!glnx_fchmod (tmpf.fd, 0644, error)) + return FALSE; + } + + const char *actual_checksum = NULL; + g_autofree char *actual_payload_checksum = NULL; + g_autofree char *actual_checksum_owned = NULL; + if (!checksum_input) + actual_checksum = expected_checksum; + else + { + actual_checksum = actual_checksum_owned = ot_checksum_instream_get_string (checksum_input); + if (expected_checksum) + { + if (!_ostree_compare_object_checksum (OSTREE_OBJECT_TYPE_FILE, expected_checksum, actual_checksum, + error)) + return FALSE; + } + + if (checksum_payload_input) + actual_payload_checksum = ot_checksum_instream_get_string (checksum_payload_input); + } + + g_assert (actual_checksum != NULL); /* Pacify static analysis */ + + /* Update size metadata if configured and entry missing */ + if (self->generate_sizes && + !repo_has_size_entry (self, OSTREE_OBJECT_TYPE_FILE, actual_checksum)) + { + struct stat stbuf; + + if (!glnx_fstat (tmpf.fd, &stbuf, error)) + return FALSE; + + repo_store_size_entry (self, OSTREE_OBJECT_TYPE_FILE, actual_checksum, + unpacked_size, stbuf.st_size); + } + + /* See whether or not we have the object, now that we know the + * checksum. + */ + gboolean have_obj; + if (!_ostree_repo_has_loose_object (self, actual_checksum, OSTREE_OBJECT_TYPE_FILE, + &have_obj, cancellable, error)) + return FALSE; + /* If we already have it, just update the stats. */ + if (have_obj) + { + g_mutex_lock (&self->txn_lock); + self->txn.stats.content_objects_total++; + g_mutex_unlock (&self->txn_lock); + + if (!_create_payload_link (self, actual_checksum, actual_payload_checksum, file_info, cancellable, error)) + return FALSE; + + if (out_csum) + *out_csum = ostree_checksum_to_bytes (actual_checksum); + /* Note early return */ + return TRUE; + } + + const guint32 uid = g_file_info_get_attribute_uint32 (file_info, "unix::uid"); + const guint32 gid = g_file_info_get_attribute_uint32 (file_info, "unix::gid"); + const guint32 mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + /* Is it "physically" a symlink? */ + if (phys_object_is_symlink) + { + if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) + { + /* We don't store the metadata in bare-user-only, so we're done. */ + } + else if (self->mode == OSTREE_REPO_MODE_BARE) + { + /* Now that we know the checksum is valid, apply uid/gid, mode bits, + * and extended attributes. + * + * Note, this does not apply for bare-user repos, as they store symlinks + * as regular files. + */ + if (G_UNLIKELY (fchownat (tmp_unlinker.dfd, tmp_unlinker.path, + uid, gid, AT_SYMLINK_NOFOLLOW) == -1)) + return glnx_throw_errno_prefix (error, "fchownat"); + + if (xattrs != NULL) + { + ot_security_smack_reset_dfd_name (tmp_unlinker.dfd, tmp_unlinker.path); + if (!glnx_dfd_name_set_all_xattrs (tmp_unlinker.dfd, tmp_unlinker.path, + xattrs, cancellable, error)) + return FALSE; + } + } + else + { + /* We don't do symlinks in archive or bare-user */ + g_assert_not_reached (); + } + + if (!commit_path_final (self, actual_checksum, OSTREE_OBJECT_TYPE_FILE, + &tmp_unlinker, cancellable, error)) + return FALSE; + } + else + { + /* Check if a file with the same payload is present in the repository, + and in case try to reflink it */ + if (actual_payload_checksum && !_try_clone_from_payload_link (self, self, actual_payload_checksum, file_info, &tmpf, cancellable, error)) + return FALSE; + + /* This path is for regular files */ + if (!commit_loose_regfile_object (self, actual_checksum, &tmpf, + uid, gid, mode, + xattrs, + cancellable, error)) + return FALSE; + + if (!_create_payload_link (self, actual_checksum, actual_payload_checksum, file_info, cancellable, error)) + return FALSE; + } + + /* Update statistics */ + g_mutex_lock (&self->txn_lock); + self->txn.stats.content_objects_written++; + self->txn.stats.content_bytes_written += g_file_info_get_size (file_info); + self->txn.stats.content_objects_total++; + g_mutex_unlock (&self->txn_lock); + + if (out_csum) + { + g_assert (actual_checksum); + *out_csum = ostree_checksum_to_bytes (actual_checksum); + } + + return TRUE; +} + +/* A fast path for local commits to `bare` or `bare-user-only` + * repos - we basically checksum the file and do a renameat() + * into place. + * + * This could be enhanced down the line to handle cases where we have a modified + * stat struct in place; e.g. for `bare` we could do the `chown`, or chmod etc., + * and reset the xattrs. + * + * We could also do this for bare-user, would just involve adding the xattr (and + * potentially deleting other ones...not sure if we'd really want e.g. the + * security.selinux xattr on setuid binaries and the like to live on). + */ +static gboolean +adopt_and_commit_regfile (OstreeRepo *self, + int dfd, + const char *name, + GFileInfo *finfo, + GVariant *xattrs, + char *out_checksum_buf, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Commit regfile (adopt)", error); + + g_assert (G_IN_SET (self->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER_ONLY)); + g_autoptr(GBytes) header = _ostree_file_header_new (finfo, xattrs); + + g_auto(OtChecksum) hasher = { 0, }; + ot_checksum_init (&hasher); + ot_checksum_update_bytes (&hasher, header); + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd, name, FALSE, &fd, error)) + return FALSE; + + (void)posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL); + + /* See also https://gist.github.com/cgwalters/0df0d15199009664549618c2188581f0 + * and https://github.com/coreutils/coreutils/blob/master/src/ioblksize.h + * Turns out bigger block size is better; down the line we should use their + * same heuristics. + */ + char buf[16*1024]; + while (TRUE) + { + ssize_t bytes_read = read (fd, buf, sizeof (buf)); + if (bytes_read < 0) + return glnx_throw_errno_prefix (error, "read"); + if (bytes_read == 0) + break; + + ot_checksum_update (&hasher, (guint8*)buf, bytes_read); + } + + ot_checksum_get_hexdigest (&hasher, out_checksum_buf, OSTREE_SHA256_STRING_LEN+1); + const char *checksum = out_checksum_buf; + + /* TODO: dedup this with commit_path_final() */ + char loose_path[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (loose_path, checksum, OSTREE_OBJECT_TYPE_FILE, self->mode); + + const guint32 src_dev = g_file_info_get_attribute_uint32 (finfo, "unix::device"); + const guint64 src_inode = g_file_info_get_attribute_uint64 (finfo, "unix::inode"); + + int dest_dfd = commit_dest_dfd (self); + if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, loose_path, + cancellable, error)) + return FALSE; + + struct stat dest_stbuf; + if (!glnx_fstatat_allow_noent (dest_dfd, loose_path, &dest_stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + /* Is the source actually the same device/inode? This can happen with hardlink + * checkouts, which is a bit overly conservative for bare-user-only right now. + * If so, we can't use renameat() since from `man 2 renameat`: + * + * "If oldpath and newpath are existing hard links referring to the same file, + * then rename() does nothing, and returns a success status." + */ + if (errno != ENOENT + && src_dev == dest_stbuf.st_dev + && src_inode == dest_stbuf.st_ino) + { + if (!glnx_unlinkat (dfd, name, 0, error)) + return FALSE; + + /* Early return */ + return TRUE; + } + + /* For bare-user-only we need to canonicalize perms */ + if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) + { + const guint32 src_mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode"); + if (fchmod (fd, src_mode & 0755) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + } + if (renameat (dfd, name, dest_dfd, loose_path) == -1) + { + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "Storing file '%s'", name); + /* We took ownership here, so delete it */ + if (!glnx_unlinkat (dfd, name, 0, error)) + return FALSE; + } + + return TRUE; +} + +/* Main driver for writing a metadata (non-content) object. */ +static gboolean +write_metadata_object (OstreeRepo *self, + OstreeObjectType objtype, + const char *expected_checksum, + GBytes *buf, + guchar **out_csum, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Writing metadata object", error); + + g_return_val_if_fail (expected_checksum || out_csum, FALSE); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + /* In the metadata case, we're not streaming, so we don't bother creating a + * tempfile until we compute the checksum. Some metadata like dirmeta is + * commonly duplicated, and computing the checksum is going to be cheaper than + * making a tempfile. + * + * However, tombstone commit types don't make sense to checksum, because for + * historical reasons we used ostree_repo_write_metadata_trusted() with the + * *original* sha256 to say what commit was being killed. + */ + const gboolean is_tombstone = (objtype == OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT); + char actual_checksum[OSTREE_SHA256_STRING_LEN+1]; + if (is_tombstone) + { + g_assert (expected_checksum != NULL); + memcpy (actual_checksum, expected_checksum, sizeof (actual_checksum)); + } + else + { + g_auto(OtChecksum) checksum = { 0, }; + ot_checksum_init (&checksum); + gsize len; + const guint8*bufdata = g_bytes_get_data (buf, &len); + ot_checksum_update (&checksum, bufdata, len); + ot_checksum_get_hexdigest (&checksum, actual_checksum, sizeof (actual_checksum)); + gboolean have_obj; + if (!_ostree_repo_has_loose_object (self, actual_checksum, objtype, &have_obj, + cancellable, error)) + return FALSE; + /* If we already have the object, we just need to update the tried-to-commit + * stat for metadata and be done here. + */ + if (have_obj) + { + /* Update size metadata if needed */ + if (self->generate_sizes && + !repo_has_size_entry (self, objtype, actual_checksum)) + repo_store_size_entry (self, objtype, actual_checksum, len, len); + + g_mutex_lock (&self->txn_lock); + self->txn.stats.metadata_objects_total++; + g_mutex_unlock (&self->txn_lock); + + if (out_csum) + *out_csum = ostree_checksum_to_bytes (actual_checksum); + /* Note early return */ + return TRUE; + } + + if (expected_checksum) + { + if (!_ostree_compare_object_checksum (objtype, expected_checksum, actual_checksum, error)) + return FALSE; + } + } + + /* Ok, checksum is known, let's get the data */ + gsize len; + const guint8 *bufp = g_bytes_get_data (buf, &len); + + /* Update size metadata if needed */ + if (self->generate_sizes && + !repo_has_size_entry (self, objtype, actual_checksum)) + repo_store_size_entry (self, objtype, actual_checksum, len, len); + + /* Write the metadata to a temporary file */ + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", O_WRONLY|O_CLOEXEC, + &tmpf, error)) + return FALSE; + if (!glnx_try_fallocate (tmpf.fd, 0, len, error)) + return FALSE; + if (glnx_loop_write (tmpf.fd, bufp, len) < 0) + return glnx_throw_errno_prefix (error, "write()"); + if (!glnx_fchmod (tmpf.fd, 0644, error)) + return FALSE; + + /* And commit it into place */ + if (!_ostree_repo_commit_tmpf_final (self, actual_checksum, objtype, + &tmpf, cancellable, error)) + return FALSE; + + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + GError *local_error = NULL; + /* If we are writing a commit, be sure there is no tombstone for it. + We may have deleted the commit and now we are trying to pull it again. */ + if (!ostree_repo_delete_object (self, + OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT, + actual_checksum, + cancellable, + &local_error)) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + g_clear_error (&local_error); + else + { + g_propagate_error (error, local_error); + return FALSE; + } + } + } + + /* Update the stats, note we both wrote one and add to total */ + g_mutex_lock (&self->txn_lock); + self->txn.stats.metadata_objects_written++; + self->txn.stats.metadata_objects_total++; + g_mutex_unlock (&self->txn_lock); + + if (out_csum) + *out_csum = ostree_checksum_to_bytes (actual_checksum); + return TRUE; +} + +/* Look in a single subdirectory of objects/, building up the + * (device,inode) → checksum map. + */ +static gboolean +scan_one_loose_devino (OstreeRepo *self, + int object_dir_fd, + GHashTable *devino_cache, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_at (object_dir_fd, ".", FALSE, + &dfd_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent; + g_auto(GLnxDirFdIterator) child_dfd_iter = { 0, }; + + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + /* All object directories only have two character entries */ + if (strlen (dent->d_name) != 2) + continue; + + if (!glnx_dirfd_iterator_init_at (dfd_iter.fd, dent->d_name, FALSE, + &child_dfd_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *child_dent; + + if (!glnx_dirfd_iterator_next_dent (&child_dfd_iter, &child_dent, cancellable, error)) + return FALSE; + if (child_dent == NULL) + break; + + const char *name = child_dent->d_name; + + gboolean skip; + switch (self->mode) + { + case OSTREE_REPO_MODE_ARCHIVE: + case OSTREE_REPO_MODE_BARE: + case OSTREE_REPO_MODE_BARE_USER: + case OSTREE_REPO_MODE_BARE_USER_ONLY: + skip = !g_str_has_suffix (name, ".file"); + break; + default: + g_assert_not_reached (); + } + if (skip) + continue; + + const char *dot = strrchr (name, '.'); + g_assert (dot); + + /* Skip anything that doesn't look like a 64 character checksum */ + if ((dot - name) != 62) + continue; + + struct stat stbuf; + if (!glnx_fstatat (child_dfd_iter.fd, child_dent->d_name, + &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + OstreeDevIno *key = g_new (OstreeDevIno, 1); + key->dev = stbuf.st_dev; + key->ino = stbuf.st_ino; + memcpy (key->checksum, dent->d_name, 2); + memcpy (key->checksum + 2, name, 62); + key->checksum[sizeof(key->checksum)-1] = '\0'; + g_hash_table_add (devino_cache, key); + } + } + + return TRUE; +} + +/* Used by ostree_repo_scan_hardlinks(); see that function for more information. */ +static gboolean +scan_loose_devino (OstreeRepo *self, + GHashTable *devino_cache, + GCancellable *cancellable, + GError **error) +{ + if (self->parent_repo) + { + if (!scan_loose_devino (self->parent_repo, devino_cache, cancellable, error)) + return FALSE; + } + + if (self->mode == OSTREE_REPO_MODE_ARCHIVE && + self->uncompressed_objects_dir_fd != -1) + { + if (!scan_one_loose_devino (self, self->uncompressed_objects_dir_fd, devino_cache, + cancellable, error)) + return FALSE; + } + + if (!scan_one_loose_devino (self, self->objects_dir_fd, + devino_cache, cancellable, error)) + return FALSE; + + return TRUE; +} + +/* Loook up a (device,inode) pair in our cache, and see if it maps to a known + * checksum. */ +static const char * +devino_cache_lookup (OstreeRepo *self, + OstreeRepoCommitModifier *modifier, + guint32 device, + guint32 inode) +{ + OstreeDevIno dev_ino_key; + OstreeDevIno *dev_ino_val; + GHashTable *cache; + + if (self->loose_object_devino_hash) + cache = self->loose_object_devino_hash; + else if (modifier && modifier->devino_cache) + cache = modifier->devino_cache; + else + return NULL; + + dev_ino_key.dev = device; + dev_ino_key.ino = inode; + dev_ino_val = g_hash_table_lookup (cache, &dev_ino_key); + if (!dev_ino_val) + return NULL; + return dev_ino_val->checksum; +} + +/** + * ostree_repo_scan_hardlinks: + * @self: An #OstreeRepo + * @cancellable: Cancellable + * @error: Error + * + * This function is deprecated in favor of using ostree_repo_devino_cache_new(), + * which allows a precise mapping to be built up between hardlink checkout files + * and their checksums between `ostree_repo_checkout_at()` and + * `ostree_repo_write_directory_to_mtree()`. + * + * When invoking ostree_repo_write_directory_to_mtree(), it has to compute the + * checksum of all files. If your commit contains hardlinks from a checkout, + * this functions builds a mapping of device numbers and inodes to their + * checksum. + * + * There is an upfront cost to creating this mapping, as this will scan the + * entire objects directory. If your commit is composed of mostly hardlinks to + * existing ostree objects, then this will speed up considerably, so call it + * before you call ostree_repo_write_directory_to_mtree() or similar. However, + * ostree_repo_devino_cache_new() is better as it avoids scanning all objects. + * + * Multithreading: This function is *not* MT safe. + */ +gboolean +ostree_repo_scan_hardlinks (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (self->in_transaction == TRUE, FALSE); + + if (!self->loose_object_devino_hash) + self->loose_object_devino_hash = (GHashTable*)ostree_repo_devino_cache_new (); + g_hash_table_remove_all (self->loose_object_devino_hash); + return scan_loose_devino (self, self->loose_object_devino_hash, cancellable, error); +} + +/** + * ostree_repo_prepare_transaction: + * @self: An #OstreeRepo + * @out_transaction_resume: (allow-none) (out): Whether this transaction + * is resuming from a previous one. This is a legacy state, now OSTree + * pulls use per-commit `state/.commitpartial` files. + * @cancellable: Cancellable + * @error: Error + * + * Starts or resumes a transaction. In order to write to a repo, you + * need to start a transaction. You can complete the transaction with + * ostree_repo_commit_transaction(), or abort the transaction with + * ostree_repo_abort_transaction(). + * + * Currently, transactions may result in partial commits or data in the target + * repository if interrupted during ostree_repo_commit_transaction(), and + * further writing refs is also not currently atomic. + * + * There can be at most one transaction active on a repo at a time per instance + * of `OstreeRepo`; however, it is safe to have multiple threads writing objects + * on a single `OstreeRepo` instance as long as their lifetime is bounded by the + * transaction. + * + * Locking: Acquires a `shared` lock; release via commit or abort + * Multithreading: This function is *not* MT safe; only one transaction can be + * active at a time. + */ +gboolean +ostree_repo_prepare_transaction (OstreeRepo *self, + gboolean *out_transaction_resume, + GCancellable *cancellable, + GError **error) +{ + guint64 reserved_bytes = 0; + + g_return_val_if_fail (self->in_transaction == FALSE, FALSE); + + g_debug ("Preparing transaction in repository %p", self); + + /* Set up to abort the transaction if we return early from this function. */ + g_autoptr(_OstreeRepoAutoTransaction) txn = self; + (void) txn; /* Add use to silence static analysis */ + + memset (&self->txn.stats, 0, sizeof (OstreeRepoTransactionStats)); + + self->txn_locked = _ostree_repo_lock_push (self, OSTREE_REPO_LOCK_SHARED, + cancellable, error); + if (!self->txn_locked) + return FALSE; + + self->in_transaction = TRUE; + self->cleanup_stagedir = FALSE; + + struct statvfs stvfsbuf; + if (TEMP_FAILURE_RETRY (fstatvfs (self->repo_dir_fd, &stvfsbuf)) < 0) + return glnx_throw_errno_prefix (error, "fstatvfs"); + + g_mutex_lock (&self->txn_lock); + self->txn.blocksize = stvfsbuf.f_bsize; + if (!ostree_repo_get_min_free_space_bytes (self, &reserved_bytes, error)) + { + g_mutex_unlock (&self->txn_lock); + return FALSE; + } + self->reserved_blocks = reserved_bytes / self->txn.blocksize; + + /* Use the appropriate free block count if we're unprivileged */ + guint64 bfree = (getuid () != 0 ? stvfsbuf.f_bavail : stvfsbuf.f_bfree); + if (bfree > self->reserved_blocks) + self->txn.max_blocks = bfree - self->reserved_blocks; + else + { + self->txn.max_blocks = 0; + /* Don't throw_min_free_space_error here; reason being that + * this transaction could be just committing metadata objects + * which are relatively small in size and we do not really + * want to block them via min-free-space-* value. Metadata + * objects helps in housekeeping and hence should be kept + * out of the strict min-free-space values. + * + * The main drivers for writing content objects will always honor + * the min-free-space value and throw_min_free_space_error in + * case of overstepping the number of reserved blocks. + */ + } + g_mutex_unlock (&self->txn_lock); + + gboolean ret_transaction_resume = FALSE; + if (!_ostree_repo_allocate_tmpdir (self->tmp_dir_fd, + self->stagedir_prefix, + &self->commit_stagedir, + &self->commit_stagedir_lock, + &ret_transaction_resume, + cancellable, error)) + return FALSE; + + /* Success: do not abort the transaction when returning. */ + txn = NULL; (void) txn; + + if (out_transaction_resume) + *out_transaction_resume = ret_transaction_resume; + return TRUE; +} + +/* Synchronize the directories holding the objects */ +static gboolean +fsync_object_dirs (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("fsync objdirs", error); + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + + if (self->disable_fsync) + return TRUE; /* No fsync? Nothing to do then. */ + + if (!glnx_dirfd_iterator_init_at (self->objects_dir_fd, ".", FALSE, &dfd_iter, error)) + return FALSE; + while (TRUE) + { + struct dirent *dent; + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + if (dent->d_type != DT_DIR) + continue; + /* All object directories only have two character entries */ + if (strlen (dent->d_name) != 2) + continue; + + glnx_autofd int target_dir_fd = -1; + if (!glnx_opendirat (self->objects_dir_fd, dent->d_name, FALSE, + &target_dir_fd, error)) + return FALSE; + /* This synchronizes the directory to ensure all the objects we wrote + * are there. We need to do this before removing the .commitpartial + * stamp (or have a ref point to the commit). + */ + if (fsync (target_dir_fd) == -1) + return glnx_throw_errno_prefix (error, "fsync"); + } + + /* In case we created any loose object subdirs, make sure they are on disk */ + if (fsync (self->objects_dir_fd) == -1) + return glnx_throw_errno_prefix (error, "fsync"); + + return TRUE; +} + +/* Called for commit, to iterate over the "staging" directory and rename all the + * objects into the primary objects/ location. Notably this is called only after + * syncfs() has potentially been invoked to ensure that all objects have been + * written to disk. In the future we may enhance this; see + * https://github.com/ostreedev/ostree/issues/1184 + */ +static gboolean +rename_pending_loose_objects (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("rename pending", error); + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + + if (!glnx_dirfd_iterator_init_at (self->commit_stagedir.fd, ".", FALSE, &dfd_iter, error)) + return FALSE; + + /* Iterate over the outer checksum dir */ + while (TRUE) + { + struct dirent *dent; + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (dent->d_type != DT_DIR) + continue; + + /* All object directories only have two character entries */ + if (strlen (dent->d_name) != 2) + continue; + + g_auto(GLnxDirFdIterator) child_dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_at (dfd_iter.fd, dent->d_name, FALSE, + &child_dfd_iter, error)) + return FALSE; + + char loose_objpath[_OSTREE_LOOSE_PATH_MAX]; + loose_objpath[0] = dent->d_name[0]; + loose_objpath[1] = dent->d_name[1]; + loose_objpath[2] = '/'; + + /* Iterate over inner checksum dir */ + while (TRUE) + { + struct dirent *child_dent; + + if (!glnx_dirfd_iterator_next_dent (&child_dfd_iter, &child_dent, cancellable, error)) + return FALSE; + if (child_dent == NULL) + break; + + g_strlcpy (loose_objpath + 3, child_dent->d_name, sizeof (loose_objpath)-3); + + if (!_ostree_repo_ensure_loose_objdir_at (self->objects_dir_fd, loose_objpath, + cancellable, error)) + return FALSE; + + if (!glnx_renameat (child_dfd_iter.fd, loose_objpath + 3, + self->objects_dir_fd, loose_objpath, error)) + return FALSE; + } + } + + return TRUE; +} + +/* Try to lock and delete a transaction stage directory created by + * ostree_repo_prepare_transaction(). + */ +static gboolean +cleanup_txn_dir (OstreeRepo *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + const char *errprefix = glnx_strjoina ("Cleaning up txn dir ", path); + GLNX_AUTO_PREFIX_ERROR (errprefix, error); + + g_auto(GLnxLockFile) lockfile = { 0, }; + gboolean did_lock; + + /* Try to lock, but if we don't get it, move on */ + if (!_ostree_repo_try_lock_tmpdir (dfd, path, &lockfile, &did_lock, error)) + return FALSE; + if (!did_lock) + return TRUE; /* Note early return */ + + /* If however this is the staging directory for the *current* + * boot, then don't delete it now - we may end up reusing it, as + * is the point. Delete *only if* we have hit min-free-space* checks + * as we don't want to hold onto caches in that case. + */ + if (g_str_has_prefix (path, self->stagedir_prefix) && !self->cleanup_stagedir) + return TRUE; /* Note early return */ + + /* But, crucially we can now clean up staging directories + * from *other* boots. + */ + if (!glnx_shutil_rm_rf_at (dfd, path, cancellable, error)) + return glnx_prefix_error (error, "Removing %s", path); + + return TRUE; +} + +/* Look in repo/tmp and delete files that are older than a day (by default). + * This used to be primarily used by the libsoup fetcher which stored partially + * written objects. In practice now that that isn't done anymore, we should + * use different logic here. Some more information in + * https://github.com/ostreedev/ostree/issues/713 + */ +static gboolean +cleanup_tmpdir (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("tmpdir cleanup", error); + const guint64 curtime_secs = g_get_real_time () / 1000000; + + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_at (self->tmp_dir_fd, ".", TRUE, &dfd_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent; + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + /* Special case this; we create it when opening, and don't want + * to blow it away. + */ + if (strcmp (dent->d_name, "cache") == 0) + continue; + + struct stat stbuf; + if (!glnx_fstatat_allow_noent (dfd_iter.fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == ENOENT) /* Did another cleanup win? */ + continue; + + /* Handle transaction tmpdirs */ + if (_ostree_repo_has_staging_prefix (dent->d_name) && S_ISDIR (stbuf.st_mode)) + { + if (!cleanup_txn_dir (self, dfd_iter.fd, dent->d_name, cancellable, error)) + return FALSE; + continue; /* We've handled this, move on */ + } + + /* At this point we're looking at an unknown-origin file or directory in + * the tmpdir. This could be something like a temporary checkout dir (used + * by rpm-ostree), or (from older versions of libostree) a tempfile if we + * don't have O_TMPFILE for commits. + */ + + /* Ignore files from the future */ + if (stbuf.st_mtime > curtime_secs) + continue; + + /* We're pruning content based on the expiry, which + * defaults to a day. That's what we were doing before we + * had locking...but in future we can be smarter here. + */ + guint64 delta = curtime_secs - stbuf.st_mtime; + if (delta > self->tmp_expiry_seconds) + { + if (!glnx_shutil_rm_rf_at (dfd_iter.fd, dent->d_name, cancellable, error)) + return glnx_prefix_error (error, "Removing %s", dent->d_name); + } + } + + return TRUE; +} + +static void +ensure_txn_refs (OstreeRepo *self) +{ + if (self->txn.refs == NULL) + self->txn.refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + if (self->txn.collection_refs == NULL) + self->txn.collection_refs = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + (GDestroyNotify) ostree_collection_ref_free, + g_free); +} + +/** + * ostree_repo_mark_commit_partial_reason: + * @self: Repo + * @checksum: Commit SHA-256 + * @is_partial: Whether or not this commit is partial + * @in_state: Reason bitmask for partial commit + * @error: Error + * + * Allows the setting of a reason code for a partial commit. Presently + * it only supports setting reason bitmask to + * OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL, or + * OSTREE_REPO_COMMIT_STATE_NORMAL. This will allow successive ostree + * fsck operations to exit properly with an error code if the + * repository has been truncated as a result of fsck trying to repair + * it. + * + * Since: 2019.4 + */ +gboolean +ostree_repo_mark_commit_partial_reason (OstreeRepo *self, + const char *checksum, + gboolean is_partial, + OstreeRepoCommitState in_state, + GError **error) +{ + g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (checksum); + if (is_partial) + { + glnx_autofd int fd = openat (self->repo_dir_fd, commitpartial_path, + O_EXCL | O_CREAT | O_WRONLY | O_CLOEXEC | O_NOCTTY, 0644); + if (fd == -1) + { + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "open(%s)", commitpartial_path); + } + else + { + if (in_state & OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL) + if (glnx_loop_write (fd, "f", 1) < 0) + return glnx_throw_errno_prefix (error, "write(%s)", commitpartial_path); + } + } + else + { + if (!ot_ensure_unlinked_at (self->repo_dir_fd, commitpartial_path, 0)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_repo_mark_commit_partial: + * @self: Repo + * @checksum: Commit SHA-256 + * @is_partial: Whether or not this commit is partial + * @error: Error + * + * Commits in the "partial" state do not have all their child objects + * written. This occurs in various situations, such as during a pull, + * but also if a "subpath" pull is used, as well as "commit only" + * pulls. + * + * This function is used by ostree_repo_pull_with_options(); you + * should use this if you are implementing a different type of transport. + * + * Since: 2017.15 + */ +gboolean +ostree_repo_mark_commit_partial (OstreeRepo *self, + const char *checksum, + gboolean is_partial, + GError **error) +{ + return ostree_repo_mark_commit_partial_reason (self, checksum, is_partial, + OSTREE_REPO_COMMIT_STATE_NORMAL, + error); +} + +/** + * ostree_repo_transaction_set_refspec: + * @self: An #OstreeRepo + * @refspec: The refspec to write + * @checksum: (nullable): The checksum to point it to + * + * Like ostree_repo_transaction_set_ref(), but takes concatenated + * @refspec format as input instead of separate remote and name + * arguments. + * + * Multithreading: Since v2017.15 this function is MT safe. + */ +void +ostree_repo_transaction_set_refspec (OstreeRepo *self, + const char *refspec, + const char *checksum) +{ + g_return_if_fail (self->in_transaction == TRUE); + + g_mutex_lock (&self->txn_lock); + ensure_txn_refs (self); + g_hash_table_replace (self->txn.refs, g_strdup (refspec), g_strdup (checksum)); + g_mutex_unlock (&self->txn_lock); +} + +/** + * ostree_repo_transaction_set_ref: + * @self: An #OstreeRepo + * @remote: (allow-none): A remote for the ref + * @ref: The ref to write + * @checksum: (nullable): The checksum to point it to + * + * If @checksum is not %NULL, then record it as the target of ref named + * @ref; if @remote is provided, the ref will appear to originate from that + * remote. + * + * Otherwise, if @checksum is %NULL, then record that the ref should + * be deleted. + * + * The change will be written when the transaction is completed with + * ostree_repo_commit_transaction(); that function takes care of writing all of + * the objects (such as the commit referred to by @checksum) before updating the + * refs. If the transaction is instead aborted with + * ostree_repo_abort_transaction(), no changes to the ref will be made to the + * repository. + * + * Note however that currently writing *multiple* refs is not truly atomic; if + * the process or system is terminated during + * ostree_repo_commit_transaction(), it is possible that just some of the refs + * will have been updated. Your application should take care to handle this + * case. + * + * Multithreading: Since v2017.15 this function is MT safe. + */ +void +ostree_repo_transaction_set_ref (OstreeRepo *self, + const char *remote, + const char *ref, + const char *checksum) +{ + g_return_if_fail (self->in_transaction == TRUE); + + char *refspec; + if (remote) + refspec = g_strdup_printf ("%s:%s", remote, ref); + else + refspec = g_strdup (ref); + + g_mutex_lock (&self->txn_lock); + ensure_txn_refs (self); + g_hash_table_replace (self->txn.refs, refspec, g_strdup (checksum)); + g_mutex_unlock (&self->txn_lock); +} + +/** + * ostree_repo_transaction_set_collection_ref: + * @self: An #OstreeRepo + * @ref: The collection–ref to write + * @checksum: (nullable): The checksum to point it to + * + * If @checksum is not %NULL, then record it as the target of local ref named + * @ref. + * + * Otherwise, if @checksum is %NULL, then record that the ref should + * be deleted. + * + * The change will not be written out immediately, but when the transaction + * is completed with ostree_repo_commit_transaction(). If the transaction + * is instead aborted with ostree_repo_abort_transaction(), no changes will + * be made to the repository. + * + * Multithreading: Since v2017.15 this function is MT safe. + * + * Since: 2018.6 + */ +void +ostree_repo_transaction_set_collection_ref (OstreeRepo *self, + const OstreeCollectionRef *ref, + const char *checksum) +{ + g_return_if_fail (OSTREE_IS_REPO (self)); + g_return_if_fail (self->in_transaction == TRUE); + g_return_if_fail (ref != NULL); + g_return_if_fail (checksum == NULL || ostree_validate_checksum_string (checksum, NULL)); + + g_mutex_lock (&self->txn_lock); + ensure_txn_refs (self); + g_hash_table_replace (self->txn.collection_refs, + ostree_collection_ref_dup (ref), g_strdup (checksum)); + g_mutex_unlock (&self->txn_lock); +} + +/** + * ostree_repo_set_ref_immediate: + * @self: An #OstreeRepo + * @remote: (allow-none): A remote for the ref + * @ref: The ref to write + * @checksum: (allow-none): The checksum to point it to, or %NULL to unset + * @cancellable: GCancellable + * @error: GError + * + * This is like ostree_repo_transaction_set_ref(), except it may be + * invoked outside of a transaction. This is presently safe for the + * case where we're creating or overwriting an existing ref. + * + * Multithreading: This function is MT safe. + */ +gboolean +ostree_repo_set_ref_immediate (OstreeRepo *self, + const char *remote, + const char *ref, + const char *checksum, + GCancellable *cancellable, + GError **error) +{ + const OstreeCollectionRef _ref = { NULL, (gchar *) ref }; + return _ostree_repo_write_ref (self, remote, &_ref, checksum, NULL, + cancellable, error); +} + +/** + * ostree_repo_set_alias_ref_immediate: + * @self: An #OstreeRepo + * @remote: (allow-none): A remote for the ref + * @ref: The ref to write + * @target: (allow-none): The ref target to point it to, or %NULL to unset + * @cancellable: GCancellable + * @error: GError + * + * Like ostree_repo_set_ref_immediate(), but creates an alias. + * + * Since: 2017.10 + */ +gboolean +ostree_repo_set_alias_ref_immediate (OstreeRepo *self, + const char *remote, + const char *ref, + const char *target, + GCancellable *cancellable, + GError **error) +{ + const OstreeCollectionRef _ref = { NULL, (gchar *) ref }; + return _ostree_repo_write_ref (self, remote, &_ref, NULL, target, + cancellable, error); +} + +/** + * ostree_repo_set_collection_ref_immediate: + * @self: An #OstreeRepo + * @ref: The collection–ref to write + * @checksum: (nullable): The checksum to point it to, or %NULL to unset + * @cancellable: GCancellable + * @error: GError + * + * This is like ostree_repo_transaction_set_collection_ref(), except it may be + * invoked outside of a transaction. This is presently safe for the + * case where we're creating or overwriting an existing ref. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: 2018.6 + */ +gboolean +ostree_repo_set_collection_ref_immediate (OstreeRepo *self, + const OstreeCollectionRef *ref, + const char *checksum, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (ref != NULL, FALSE); + g_return_val_if_fail (checksum == NULL || ostree_validate_checksum_string (checksum, NULL), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + return _ostree_repo_write_ref (self, NULL, ref, checksum, NULL, + cancellable, error); +} + +/** + * ostree_repo_commit_transaction: + * @self: An #OstreeRepo + * @out_stats: (allow-none) (out): A set of statistics of things + * that happened during this transaction. + * @cancellable: Cancellable + * @error: Error + * + * Complete the transaction. Any refs set with + * ostree_repo_transaction_set_ref() or + * ostree_repo_transaction_set_refspec() will be written out. + * + * Note that if multiple threads are performing writes, all such threads must + * have terminated before this function is invoked. + * + * Locking: Releases `shared` lock acquired by `ostree_repo_prepare_transaction()` + * Multithreading: This function is *not* MT safe; only one transaction can be + * active at a time. + */ +gboolean +ostree_repo_commit_transaction (OstreeRepo *self, + OstreeRepoTransactionStats *out_stats, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (self->in_transaction == TRUE, FALSE); + + g_debug ("Committing transaction in repository %p", self); + + if ((self->test_error_flags & OSTREE_REPO_TEST_ERROR_PRE_COMMIT) > 0) + return glnx_throw (error, "OSTREE_REPO_TEST_ERROR_PRE_COMMIT specified"); + + /* FIXME: Added OSTREE_SUPPRESS_SYNCFS since valgrind in el7 doesn't know + * about `syncfs`...we should delete this later. + */ + if (!self->disable_fsync && + g_getenv ("OSTREE_SUPPRESS_SYNCFS") == NULL) + { + if (syncfs (self->tmp_dir_fd) < 0) + return glnx_throw_errno_prefix (error, "syncfs"); + } + + if (!rename_pending_loose_objects (self, cancellable, error)) + return FALSE; + + if (!fsync_object_dirs (self, cancellable, error)) + return FALSE; + + g_debug ("txn commit %s", glnx_basename (self->commit_stagedir.path)); + if (!glnx_tmpdir_delete (&self->commit_stagedir, cancellable, error)) + return FALSE; + glnx_release_lock_file (&self->commit_stagedir_lock); + + /* This performs a global cleanup */ + if (!cleanup_tmpdir (self, cancellable, error)) + return FALSE; + + if (self->loose_object_devino_hash) + g_hash_table_remove_all (self->loose_object_devino_hash); + + if (self->txn.refs) + if (!_ostree_repo_update_refs (self, self->txn.refs, cancellable, error)) + return FALSE; + + if (self->txn.collection_refs) + if (!_ostree_repo_update_collection_refs (self, self->txn.collection_refs, cancellable, error)) + return FALSE; + + /* Update the summary if auto-update-summary is set, because doing so was + * delayed for each ref change during the transaction. + */ + if ((self->txn.refs || self->txn.collection_refs) && + !_ostree_repo_maybe_regenerate_summary (self, cancellable, error)) + return FALSE; + + g_clear_pointer (&self->txn.refs, g_hash_table_destroy); + g_clear_pointer (&self->txn.collection_refs, g_hash_table_destroy); + + self->in_transaction = FALSE; + + if (!ot_ensure_unlinked_at (self->repo_dir_fd, "transaction", 0)) + return FALSE; + + if (self->txn_locked) + { + if (!_ostree_repo_lock_pop (self, cancellable, error)) + return FALSE; + self->txn_locked = FALSE; + } + + if (out_stats) + *out_stats = self->txn.stats; + + return TRUE; +} + +/** + * ostree_repo_abort_transaction: + * @self: An #OstreeRepo + * @cancellable: Cancellable + * @error: Error + * + * Abort the active transaction; any staged objects and ref changes will be + * discarded. You *must* invoke this if you have chosen not to invoke + * ostree_repo_commit_transaction(). Calling this function when not in a + * transaction will do nothing and return successfully. + */ +gboolean +ostree_repo_abort_transaction (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GError) cleanup_error = NULL; + + /* Always ignore the cancellable to avoid the chance that, if it gets + * canceled, the transaction may not be fully cleaned up. + * See https://github.com/ostreedev/ostree/issues/1491 . + */ + cancellable = NULL; + + /* Note early return */ + if (!self->in_transaction) + return TRUE; + + g_debug ("Aborting transaction in repository %p", self); + + if (self->loose_object_devino_hash) + g_hash_table_remove_all (self->loose_object_devino_hash); + + g_clear_pointer (&self->txn.refs, g_hash_table_destroy); + g_clear_pointer (&self->txn.collection_refs, g_hash_table_destroy); + + glnx_tmpdir_unset (&self->commit_stagedir); + glnx_release_lock_file (&self->commit_stagedir_lock); + + /* Do not propagate failures from cleanup_tmpdir() immediately, as we want + * to clean up the rest of the internal transaction state first. */ + cleanup_tmpdir (self, cancellable, &cleanup_error); + + self->in_transaction = FALSE; + + if (self->txn_locked) + { + if (!_ostree_repo_lock_pop (self, cancellable, error)) + return FALSE; + self->txn_locked = FALSE; + } + + /* Propagate cleanup_tmpdir() failure. */ + if (cleanup_error != NULL) + { + g_propagate_error (error, g_steal_pointer (&cleanup_error)); + return FALSE; + } + + return TRUE; +} + +/** + * ostree_repo_write_metadata: + * @self: Repo + * @objtype: Object type + * @expected_checksum: (allow-none): If provided, validate content against this checksum + * @object: Metadata + * @out_csum: (out) (array fixed-size=32) (allow-none): Binary checksum + * @cancellable: Cancellable + * @error: Error + * + * Store the metadata object @object. Return the checksum + * as @out_csum. + * + * If @expected_checksum is not %NULL, verify it against the + * computed checksum. + */ +gboolean +ostree_repo_write_metadata (OstreeRepo *self, + OstreeObjectType objtype, + const char *expected_checksum, + GVariant *object, + guchar **out_csum, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) normalized = NULL; + /* First, if we have an expected checksum, see if we already have this + * object. This mirrors the same logic in ostree_repo_write_content(). + */ + if (expected_checksum) + { + gboolean have_obj; + if (!_ostree_repo_has_loose_object (self, expected_checksum, objtype, &have_obj, + cancellable, error)) + return FALSE; + if (have_obj) + { + /* Update size metadata if needed */ + if (self->generate_sizes && + !repo_has_size_entry (self, objtype, expected_checksum)) + { + /* Make sure we have a fully serialized object */ + g_autoptr(GVariant) trusted = g_variant_get_normal_form (object); + gsize size = g_variant_get_size (trusted); + repo_store_size_entry (self, objtype, expected_checksum, size, size); + } + + if (out_csum) + *out_csum = ostree_checksum_to_bytes (expected_checksum); + return TRUE; + } + /* If the caller is giving us an expected checksum, the object really has + * to be normalized already. Otherwise, how would they know the checksum? + * There's no sense in redoing it. + */ + normalized = g_variant_ref (object); + } + else + { + normalized = g_variant_get_normal_form (object); + } + + /* For untrusted objects, verify their structure here */ + if (expected_checksum) + { + if (!_ostree_validate_structureof_metadata (objtype, object, error)) + return FALSE; + } + + g_autoptr(GBytes) vdata = g_variant_get_data_as_bytes (normalized); + if (!write_metadata_object (self, objtype, expected_checksum, + vdata, out_csum, cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_repo_write_metadata_stream_trusted: + * @self: Repo + * @objtype: Object type + * @checksum: Store object with this ASCII SHA256 checksum + * @object_input: Metadata object stream + * @length: Length, may be 0 for unknown + * @cancellable: Cancellable + * @error: Error + * + * Store the metadata object @variant; the provided @checksum is + * trusted. + */ +gboolean +ostree_repo_write_metadata_stream_trusted (OstreeRepo *self, + OstreeObjectType objtype, + const char *checksum, + GInputStream *object_input, + guint64 length, + GCancellable *cancellable, + GError **error) +{ + /* This is all pretty ridiculous, but we're keeping this API for backwards + * compatibility, it doesn't really need to be fast. + */ + g_autoptr(GMemoryOutputStream) tmpbuf = (GMemoryOutputStream*)g_memory_output_stream_new_resizable (); + if (g_output_stream_splice ((GOutputStream*)tmpbuf, object_input, + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, cancellable, error) < 0) + return FALSE; + g_autoptr(GBytes) tmpb = g_memory_output_stream_steal_as_bytes (tmpbuf); + + g_autoptr(GVariant) tmpv = g_variant_new_from_bytes (ostree_metadata_variant_type (objtype), + tmpb, TRUE); + return ostree_repo_write_metadata_trusted (self, objtype, checksum, tmpv, + cancellable, error); +} + +/** + * ostree_repo_write_metadata_trusted: + * @self: Repo + * @objtype: Object type + * @checksum: Store object with this ASCII SHA256 checksum + * @variant: Metadata object + * @cancellable: Cancellable + * @error: Error + * + * Store the metadata object @variant; the provided @checksum is + * trusted. + */ +gboolean +ostree_repo_write_metadata_trusted (OstreeRepo *self, + OstreeObjectType type, + const char *checksum, + GVariant *variant, + GCancellable *cancellable, + GError **error) +{ + return ostree_repo_write_metadata (self, type, + checksum, variant, NULL, + cancellable, error); +} + +typedef struct { + OstreeRepo *repo; + OstreeObjectType objtype; + char *expected_checksum; + GVariant *object; + GCancellable *cancellable; + GSimpleAsyncResult *result; + + guchar *result_csum; +} WriteMetadataAsyncData; + +static void +write_metadata_async_data_free (gpointer user_data) +{ + WriteMetadataAsyncData *data = user_data; + + g_clear_object (&data->repo); + g_clear_object (&data->cancellable); + g_variant_unref (data->object); + g_free (data->result_csum); + g_free (data->expected_checksum); + g_free (data); +} + +static void +write_metadata_thread (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + GError *error = NULL; + WriteMetadataAsyncData *data; + + data = g_simple_async_result_get_op_res_gpointer (res); + if (!ostree_repo_write_metadata (data->repo, data->objtype, data->expected_checksum, + data->object, + &data->result_csum, + cancellable, &error)) + g_simple_async_result_take_error (res, error); +} + +/** + * ostree_repo_write_metadata_async: + * @self: Repo + * @objtype: Object type + * @expected_checksum: (allow-none): If provided, validate content against this checksum + * @object: Metadata + * @cancellable: Cancellable + * @callback: Invoked when metadata is writed + * @user_data: Data for @callback + * + * Asynchronously store the metadata object @variant. If provided, + * the checksum @expected_checksum will be verified. + */ +void +ostree_repo_write_metadata_async (OstreeRepo *self, + OstreeObjectType objtype, + const char *expected_checksum, + GVariant *object, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + WriteMetadataAsyncData *asyncdata; + + asyncdata = g_new0 (WriteMetadataAsyncData, 1); + asyncdata->repo = g_object_ref (self); + asyncdata->objtype = objtype; + asyncdata->expected_checksum = g_strdup (expected_checksum); + asyncdata->object = g_variant_ref (object); + asyncdata->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + asyncdata->result = g_simple_async_result_new ((GObject*) self, + callback, user_data, + ostree_repo_write_metadata_async); + + g_simple_async_result_set_op_res_gpointer (asyncdata->result, asyncdata, + write_metadata_async_data_free); + g_simple_async_result_run_in_thread (asyncdata->result, write_metadata_thread, G_PRIORITY_DEFAULT, cancellable); + g_object_unref (asyncdata->result); +} + +/** + * ostree_repo_write_metadata_finish: + * @self: Repo + * @result: Result + * @out_csum: (out) (array fixed-size=32) (element-type guint8): Binary checksum value + * @error: Error + * + * Complete a call to ostree_repo_write_metadata_async(). + */ +gboolean +ostree_repo_write_metadata_finish (OstreeRepo *self, + GAsyncResult *result, + guchar **out_csum, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + WriteMetadataAsyncData *data; + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == ostree_repo_write_metadata_async); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + data = g_simple_async_result_get_op_res_gpointer (simple); + /* Transfer ownership */ + *out_csum = data->result_csum; + data->result_csum = NULL; + return TRUE; +} + +/* Write an object of type OSTREE_OBJECT_TYPE_DIR_META, using @file_info and @xattrs. + * Return its (binary) checksum in @out_csum. + */ +gboolean +_ostree_repo_write_directory_meta (OstreeRepo *self, + GFileInfo *file_info, + GVariant *xattrs, + guchar **out_csum, + GCancellable *cancellable, + GError **error) +{ + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + g_autoptr(GVariant) dirmeta = ostree_create_directory_metadata (file_info, xattrs); + return ostree_repo_write_metadata (self, OSTREE_OBJECT_TYPE_DIR_META, NULL, + dirmeta, out_csum, cancellable, error); +} + +/** + * ostree_repo_write_content_trusted: + * @self: Repo + * @checksum: Store content using this ASCII SHA256 checksum + * @object_input: Content stream + * @length: Length of @object_input + * @cancellable: Cancellable + * @error: Data for @callback + * + * Store the content object streamed as @object_input, with total + * length @length. The given @checksum will be treated as trusted. + * + * This function should be used when importing file objects from local + * disk, for example. + */ +gboolean +ostree_repo_write_content_trusted (OstreeRepo *self, + const char *checksum, + GInputStream *object_input, + guint64 length, + GCancellable *cancellable, + GError **error) +{ + return ostree_repo_write_content (self, checksum, object_input, length, + NULL, cancellable, error); +} + +/** + * ostree_repo_write_content: + * @self: Repo + * @expected_checksum: (allow-none): If provided, validate content against this checksum + * @object_input: Content object stream + * @length: Length of @object_input + * @out_csum: (out) (array fixed-size=32) (allow-none): Binary checksum + * @cancellable: Cancellable + * @error: Error + * + * Store the content object streamed as @object_input, + * with total length @length. The actual checksum will + * be returned as @out_csum. + */ +gboolean +ostree_repo_write_content (OstreeRepo *self, + const char *expected_checksum, + GInputStream *object_input, + guint64 length, + guchar **out_csum, + GCancellable *cancellable, + GError **error) +{ + /* First, if we have an expected checksum, see if we already have this + * object. This mirrors the same logic in ostree_repo_write_metadata(). + * + * If size metadata is needed, fall through to write_content_object() + * where the entries are made. + */ + if (expected_checksum && !self->generate_sizes) + { + gboolean have_obj; + if (!_ostree_repo_has_loose_object (self, expected_checksum, + OSTREE_OBJECT_TYPE_FILE, &have_obj, + cancellable, error)) + return FALSE; + if (have_obj) + { + if (out_csum) + *out_csum = ostree_checksum_to_bytes (expected_checksum); + return TRUE; + } + } + + /* Parse the stream */ + g_autoptr(GInputStream) file_input = NULL; + g_autoptr(GVariant) xattrs = NULL; + g_autoptr(GFileInfo) file_info = NULL; + if (!ostree_content_stream_parse (FALSE, object_input, length, FALSE, + &file_input, &file_info, &xattrs, + cancellable, error)) + return FALSE; + + return write_content_object (self, expected_checksum, + file_input, file_info, xattrs, out_csum, + cancellable, error); +} + +typedef struct { + OstreeRepo *repo; + char *expected_checksum; + GInputStream *object; + guint64 file_object_length; + GCancellable *cancellable; + GSimpleAsyncResult *result; + + guchar *result_csum; +} WriteContentAsyncData; + +static void +write_content_async_data_free (gpointer user_data) +{ + WriteContentAsyncData *data = user_data; + + g_clear_object (&data->repo); + g_clear_object (&data->cancellable); + g_clear_object (&data->object); + g_free (data->result_csum); + g_free (data->expected_checksum); + g_free (data); +} + +static void +write_content_thread (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + GError *error = NULL; + WriteContentAsyncData *data; + + data = g_simple_async_result_get_op_res_gpointer (res); + if (!ostree_repo_write_content (data->repo, data->expected_checksum, + data->object, data->file_object_length, + &data->result_csum, + cancellable, &error)) + g_simple_async_result_take_error (res, error); +} + +/** + * ostree_repo_write_content_async: + * @self: Repo + * @expected_checksum: (allow-none): If provided, validate content against this checksum + * @object: Input + * @length: Length of @object + * @cancellable: Cancellable + * @callback: Invoked when content is writed + * @user_data: User data for @callback + * + * Asynchronously store the content object @object. If provided, the + * checksum @expected_checksum will be verified. + */ +void +ostree_repo_write_content_async (OstreeRepo *self, + const char *expected_checksum, + GInputStream *object, + guint64 length, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + WriteContentAsyncData *asyncdata; + + asyncdata = g_new0 (WriteContentAsyncData, 1); + asyncdata->repo = g_object_ref (self); + asyncdata->expected_checksum = g_strdup (expected_checksum); + asyncdata->object = g_object_ref (object); + asyncdata->file_object_length = length; + asyncdata->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + asyncdata->result = g_simple_async_result_new ((GObject*) self, + callback, user_data, + ostree_repo_write_content_async); + + g_simple_async_result_set_op_res_gpointer (asyncdata->result, asyncdata, + write_content_async_data_free); + g_simple_async_result_run_in_thread (asyncdata->result, write_content_thread, G_PRIORITY_DEFAULT, cancellable); + g_object_unref (asyncdata->result); +} + +/** + * ostree_repo_write_content_finish: + * @self: a #OstreeRepo + * @result: a #GAsyncResult + * @out_csum: (out) (transfer full): A binary SHA256 checksum of the content object + * @error: a #GError + * + * Completes an invocation of ostree_repo_write_content_async(). + */ +gboolean +ostree_repo_write_content_finish (OstreeRepo *self, + GAsyncResult *result, + guchar **out_csum, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + WriteContentAsyncData *data; + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == ostree_repo_write_content_async); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + + data = g_simple_async_result_get_op_res_gpointer (simple); + ot_transfer_out_value (out_csum, &data->result_csum); + return TRUE; +} + +static GVariant * +create_empty_gvariant_dict (void) +{ + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE("a{sv}")); + return g_variant_builder_end (&builder); +} + +/** + * ostree_repo_write_commit: + * @self: Repo + * @parent: (allow-none): ASCII SHA256 checksum for parent, or %NULL for none + * @subject: (allow-none): Subject + * @body: (allow-none): Body + * @metadata: (allow-none): GVariant of type a{sv}, or %NULL for none + * @root: The tree to point the commit to + * @out_commit: (out): Resulting ASCII SHA256 checksum for commit + * @cancellable: Cancellable + * @error: Error + * + * Write a commit metadata object, referencing @root_contents_checksum + * and @root_metadata_checksum. + */ +gboolean +ostree_repo_write_commit (OstreeRepo *self, + const char *parent, + const char *subject, + const char *body, + GVariant *metadata, + OstreeRepoFile *root, + char **out_commit, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GDateTime) now = g_date_time_new_now_utc (); + return ostree_repo_write_commit_with_time (self, parent, subject, body, + metadata, root, g_date_time_to_unix (now), + out_commit, cancellable, error); +} + +/** + * ostree_repo_write_commit_with_time: + * @self: Repo + * @parent: (allow-none): ASCII SHA256 checksum for parent, or %NULL for none + * @subject: (allow-none): Subject + * @body: (allow-none): Body + * @metadata: (allow-none): GVariant of type a{sv}, or %NULL for none + * @root: The tree to point the commit to + * @time: The time to use to stamp the commit + * @out_commit: (out): Resulting ASCII SHA256 checksum for commit + * @cancellable: Cancellable + * @error: Error + * + * Write a commit metadata object, referencing @root_contents_checksum + * and @root_metadata_checksum. + */ +gboolean +ostree_repo_write_commit_with_time (OstreeRepo *self, + const char *parent, + const char *subject, + const char *body, + GVariant *metadata, + OstreeRepoFile *root, + guint64 time, + char **out_commit, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoFile *repo_root = OSTREE_REPO_FILE (root); + + /* Add sizes information to our metadata object */ + g_autoptr(GVariant) new_metadata = add_size_index_to_metadata (self, metadata); + + g_autoptr(GVariant) commit = + g_variant_new ("(@a{sv}@ay@a(say)sst@ay@ay)", + new_metadata ? new_metadata : create_empty_gvariant_dict (), + parent ? ostree_checksum_to_bytes_v (parent) : ot_gvariant_new_bytearray (NULL, 0), + g_variant_new_array (G_VARIANT_TYPE ("(say)"), NULL, 0), + subject ? subject : "", body ? body : "", + GUINT64_TO_BE (time), + ostree_checksum_to_bytes_v (ostree_repo_file_tree_get_contents_checksum (repo_root)), + ostree_checksum_to_bytes_v (ostree_repo_file_tree_get_metadata_checksum (repo_root))); + g_variant_ref_sink (commit); + g_autofree guchar *commit_csum = NULL; + if (!ostree_repo_write_metadata (self, OSTREE_OBJECT_TYPE_COMMIT, NULL, + commit, &commit_csum, + cancellable, error)) + return FALSE; + + g_autofree char *ret_commit = ostree_checksum_from_bytes (commit_csum); + ot_transfer_out_value(out_commit, &ret_commit); + return TRUE; +} + +/** + * ostree_repo_read_commit_detached_metadata: + * @self: Repo + * @checksum: ASCII SHA256 commit checksum + * @out_metadata: (out) (transfer full): Metadata associated with commit in with format "a{sv}", or %NULL if none exists + * @cancellable: Cancellable + * @error: Error + * + * OSTree commits can have arbitrary metadata associated; this + * function retrieves them. If none exists, @out_metadata will be set + * to %NULL. + */ +gboolean +ostree_repo_read_commit_detached_metadata (OstreeRepo *self, + const char *checksum, + GVariant **out_metadata, + GCancellable *cancellable, + GError **error) +{ + char buf[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (buf, checksum, OSTREE_OBJECT_TYPE_COMMIT_META, self->mode); + + if (self->commit_stagedir.initialized) + { + glnx_autofd int fd = -1; + if (!ot_openat_ignore_enoent (self->commit_stagedir.fd, buf, &fd, error)) + return FALSE; + if (fd != -1) + return ot_variant_read_fd (fd, 0, G_VARIANT_TYPE ("a{sv}"), TRUE, + out_metadata, error); + } + + glnx_autofd int fd = -1; + if (!ot_openat_ignore_enoent (self->objects_dir_fd, buf, &fd, error)) + return FALSE; + if (fd != -1) + return ot_variant_read_fd (fd, 0, G_VARIANT_TYPE ("a{sv}"), TRUE, + out_metadata, error); + + if (self->parent_repo) + return ostree_repo_read_commit_detached_metadata (self->parent_repo, + checksum, out_metadata, + cancellable, error); + /* Nothing found */ + *out_metadata = NULL; + return TRUE; +} + +/** + * ostree_repo_write_commit_detached_metadata: + * @self: Repo + * @checksum: ASCII SHA256 commit checksum + * @metadata: (allow-none): Metadata to associate with commit in with format "a{sv}", or %NULL to delete + * @cancellable: Cancellable + * @error: Error + * + * Replace any existing metadata associated with commit referred to by + * @checksum with @metadata. If @metadata is %NULL, then existing + * data will be deleted. + */ +gboolean +ostree_repo_write_commit_detached_metadata (OstreeRepo *self, + const char *checksum, + GVariant *metadata, + GCancellable *cancellable, + GError **error) +{ + int dest_dfd; + if (self->in_transaction) + dest_dfd = self->commit_stagedir.fd; + else + dest_dfd = self->objects_dir_fd; + + if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, checksum, + cancellable, error)) + return FALSE; + + g_autoptr(GVariant) normalized = NULL; + gsize normalized_size = 0; + const guint8 *data = NULL; + if (metadata != NULL) + { + normalized = g_variant_get_normal_form (metadata); + normalized_size = g_variant_get_size (normalized); + data = g_variant_get_data (normalized); + } + + if (data == NULL) + data = (guint8*)""; + + char pathbuf[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (pathbuf, checksum, OSTREE_OBJECT_TYPE_COMMIT_META, self->mode); + if (!glnx_file_replace_contents_at (dest_dfd, pathbuf, + data, normalized_size, + 0, cancellable, error)) + { + g_prefix_error (error, "Unable to write detached metadata: "); + return FALSE; + } + + return TRUE; +} + +/* This generates an in-memory OSTREE_OBJECT_TYPE_DIR_TREE variant, using the + * content objects and subdirectories. The input hashes will be sorted + */ +static GVariant * +create_tree_variant_from_hashes (GHashTable *file_checksums, + GHashTable *dir_contents_checksums, + GHashTable *dir_metadata_checksums) +{ + GVariantBuilder files_builder; + g_variant_builder_init (&files_builder, G_VARIANT_TYPE ("a(say)")); + GVariantBuilder dirs_builder; + g_variant_builder_init (&dirs_builder, G_VARIANT_TYPE ("a(sayay)")); + + GSList *sorted_filenames = NULL; + GLNX_HASH_TABLE_FOREACH (file_checksums, const char*, name) + { + /* Should have been validated earlier, but be paranoid */ + g_assert (ot_util_filename_validate (name, NULL)); + + sorted_filenames = g_slist_prepend (sorted_filenames, (char*)name); + } + sorted_filenames = g_slist_sort (sorted_filenames, (GCompareFunc)strcmp); + for (GSList *iter = sorted_filenames; iter; iter = iter->next) + { + const char *name = iter->data; + const char *value; + + value = g_hash_table_lookup (file_checksums, name); + g_variant_builder_add (&files_builder, "(s@ay)", name, + ostree_checksum_to_bytes_v (value)); + } + g_slist_free (sorted_filenames); + sorted_filenames = NULL; + + GLNX_HASH_TABLE_FOREACH (dir_metadata_checksums, const char*, name) + sorted_filenames = g_slist_prepend (sorted_filenames, (char*)name); + sorted_filenames = g_slist_sort (sorted_filenames, (GCompareFunc)strcmp); + + for (GSList *iter = sorted_filenames; iter; iter = iter->next) + { + const char *name = iter->data; + const char *content_checksum = g_hash_table_lookup (dir_contents_checksums, name); + const char *meta_checksum = g_hash_table_lookup (dir_metadata_checksums, name); + + g_variant_builder_add (&dirs_builder, "(s@ay@ay)", name, + ostree_checksum_to_bytes_v (content_checksum), + ostree_checksum_to_bytes_v (meta_checksum)); + } + + g_slist_free (sorted_filenames); + sorted_filenames = NULL; + + GVariant *serialized_tree = + g_variant_new ("(@a(say)@a(sayay))", + g_variant_builder_end (&files_builder), + g_variant_builder_end (&dirs_builder)); + return g_variant_ref_sink (serialized_tree); +} + +/* If any filtering is set up, perform it, and return modified file info in + * @out_modified_info. Note that if no filtering is applied, @out_modified_info + * will simply be another reference (with incremented refcount) to @file_info. + */ +OstreeRepoCommitFilterResult +_ostree_repo_commit_modifier_apply (OstreeRepo *self, + OstreeRepoCommitModifier *modifier, + const char *path, + GFileInfo *file_info, + GFileInfo **out_modified_info) +{ + OstreeRepoCommitFilterResult result = OSTREE_REPO_COMMIT_FILTER_ALLOW; + GFileInfo *modified_info; + + if (modifier == NULL || + (modifier->filter == NULL && + (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS) == 0)) + { + *out_modified_info = g_object_ref (file_info); + return OSTREE_REPO_COMMIT_FILTER_ALLOW; + } + + modified_info = g_file_info_dup (file_info); + if (modifier->filter) + result = modifier->filter (self, path, modified_info, modifier->user_data); + + if ((modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS) != 0) + { + guint mode = g_file_info_get_attribute_uint32 (modified_info, "unix::mode"); + switch (g_file_info_get_file_type (file_info)) + { + case G_FILE_TYPE_REGULAR: + /* In particular, we want to squash the s{ug}id bits, but this also + * catches the sticky bit for example. + */ + g_file_info_set_attribute_uint32 (modified_info, "unix::mode", mode & (S_IFREG | 0755)); + break; + case G_FILE_TYPE_DIRECTORY: + /* Like the above but for directories */ + g_file_info_set_attribute_uint32 (modified_info, "unix::mode", mode & (S_IFDIR | 0755)); + break; + case G_FILE_TYPE_SYMBOLIC_LINK: + break; + default: + g_assert_not_reached (); + } + g_file_info_set_attribute_uint32 (modified_info, "unix::uid", 0); + g_file_info_set_attribute_uint32 (modified_info, "unix::gid", 0); + } + + *out_modified_info = modified_info; + + return result; +} + +/* Convert @path into a string */ +static char * +ptrarray_path_join (GPtrArray *path) +{ + GString *path_buf = g_string_new (""); + + if (path->len == 0) + g_string_append_c (path_buf, '/'); + else + { + for (guint i = 0; i < path->len; i++) + { + const char *elt = path->pdata[i]; + + g_string_append_c (path_buf, '/'); + g_string_append (path_buf, elt); + } + } + + return g_string_free (path_buf, FALSE); +} + +static gboolean +get_final_xattrs (OstreeRepo *self, + OstreeRepoCommitModifier *modifier, + const char *relpath, + GFileInfo *file_info, + GFile *path, + int dfd, + const char *dfd_subpath, + GVariant *source_xattrs, + GVariant **out_xattrs, + gboolean *out_modified, + GCancellable *cancellable, + GError **error) +{ + /* track whether the returned xattrs differ from the file on disk */ + gboolean modified = TRUE; + const gboolean skip_xattrs = (modifier && + modifier->flags & (OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS | + OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS)) > 0; + + /* fetch on-disk xattrs if needed & not disabled */ + g_autoptr(GVariant) original_xattrs = NULL; + if (!skip_xattrs && !self->disable_xattrs) + { + if (source_xattrs) + original_xattrs = g_variant_ref (source_xattrs); + else if (path && OSTREE_IS_REPO_FILE (path)) + { + if (!ostree_repo_file_get_xattrs (OSTREE_REPO_FILE (path), &original_xattrs, + cancellable, error)) + return FALSE; + } + else if (path) + { + if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (path), + &original_xattrs, cancellable, error)) + return FALSE; + } + else if (dfd_subpath == NULL) + { + g_assert (dfd != -1); + if (!glnx_fd_get_all_xattrs (dfd, &original_xattrs, cancellable, error)) + return FALSE; + } + else + { + g_assert (dfd != -1); + if (!glnx_dfd_name_get_all_xattrs (dfd, dfd_subpath, &original_xattrs, + cancellable, error)) + return FALSE; + } + + g_assert (original_xattrs); + } + + g_autoptr(GVariant) ret_xattrs = NULL; + if (modifier && modifier->xattr_callback) + { + ret_xattrs = modifier->xattr_callback (self, relpath, file_info, + modifier->xattr_user_data); + } + + /* if callback returned NULL or didn't exist, default to on-disk state */ + if (!ret_xattrs && original_xattrs) + ret_xattrs = g_variant_ref (original_xattrs); + + if (modifier && modifier->sepolicy) + { + g_autofree char *label = NULL; + + if (!ostree_sepolicy_get_label (modifier->sepolicy, relpath, + g_file_info_get_attribute_uint32 (file_info, "unix::mode"), + &label, cancellable, error)) + return FALSE; + + if (!label && (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED) > 0) + { + return glnx_throw (error, "Failed to look up SELinux label for '%s'", relpath); + } + else if (label) + { + g_autoptr(GVariantBuilder) builder = NULL; + + if (ret_xattrs) + { + /* drop out any existing SELinux policy from the set, so we don't end up + * counting it twice in the checksum */ + GVariant* new_ret_xattrs = _ostree_filter_selinux_xattr (ret_xattrs); + g_variant_unref (ret_xattrs); + ret_xattrs = new_ret_xattrs; + } + + /* ret_xattrs may be NULL */ + builder = ot_util_variant_builder_from_variant (ret_xattrs, + G_VARIANT_TYPE ("a(ayay)")); + + g_variant_builder_add_value (builder, + g_variant_new ("(@ay@ay)", + g_variant_new_bytestring ("security.selinux"), + g_variant_new_bytestring (label))); + if (ret_xattrs) + g_variant_unref (ret_xattrs); + + ret_xattrs = g_variant_builder_end (builder); + g_variant_ref_sink (ret_xattrs); + } + } + + if (original_xattrs && ret_xattrs && g_variant_equal (original_xattrs, ret_xattrs)) + modified = FALSE; + + if (out_xattrs) + *out_xattrs = g_steal_pointer (&ret_xattrs); + if (out_modified) + *out_modified = modified; + return TRUE; +} + +static gboolean +write_directory_to_mtree_internal (OstreeRepo *self, + GFile *dir, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GPtrArray *path, + GCancellable *cancellable, + GError **error); +static gboolean +write_dfd_iter_to_mtree_internal (OstreeRepo *self, + GLnxDirFdIterator *src_dfd_iter, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GPtrArray *path, + GCancellable *cancellable, + GError **error); + +typedef enum { + WRITE_DIR_CONTENT_FLAGS_NONE = 0, + WRITE_DIR_CONTENT_FLAGS_CAN_ADOPT = 1, +} WriteDirContentFlags; + +/* Given either a dir_enum or a dfd_iter, writes the directory entry (which is + * itself a directory) to the mtree. For subdirs, we go back through either + * write_dfd_iter_to_mtree_internal (dfd_iter case) or + * write_directory_to_mtree_internal (dir_enum case) which will do the actual + * dirmeta + dirent iteration. */ +static gboolean +write_dir_entry_to_mtree_internal (OstreeRepo *self, + OstreeRepoFile *repo_dir, + GFileEnumerator *dir_enum, + GLnxDirFdIterator *dfd_iter, + WriteDirContentFlags writeflags, + GFileInfo *child_info, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GPtrArray *path, + GCancellable *cancellable, + GError **error) +{ + g_assert (dir_enum != NULL || dfd_iter != NULL); + g_assert (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY); + + const char *name = g_file_info_get_name (child_info); + + /* We currently only honor the CONSUME flag in the dfd_iter case to avoid even + * more complexity in this function, and it'd mostly only be useful when + * operating on local filesystems anyways. + */ + const gboolean delete_after_commit = dfd_iter && modifier && + (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME); + + /* Build the full path which we need for callbacks */ + g_ptr_array_add (path, (char*)name); + g_autofree char *child_relpath = ptrarray_path_join (path); + + /* Call the filter */ + g_autoptr(GFileInfo) modified_info = NULL; + OstreeRepoCommitFilterResult filter_result = + _ostree_repo_commit_modifier_apply (self, modifier, child_relpath, child_info, &modified_info); + + if (filter_result != OSTREE_REPO_COMMIT_FILTER_ALLOW) + { + g_ptr_array_remove_index (path, path->len - 1); + if (delete_after_commit) + { + g_assert (dfd_iter); + if (!glnx_shutil_rm_rf_at (dfd_iter->fd, name, cancellable, error)) + return FALSE; + } + /* Note: early return */ + return TRUE; + } + + g_autoptr(GFile) child = NULL; + if (dir_enum != NULL) + child = g_file_enumerator_get_child (dir_enum, child_info); + + g_autoptr(OstreeMutableTree) child_mtree = NULL; + if (!ostree_mutable_tree_ensure_dir (mtree, name, &child_mtree, error)) + return FALSE; + + /* Finally, recurse on the dir */ + if (dir_enum != NULL) + { + if (!write_directory_to_mtree_internal (self, child, child_mtree, + modifier, path, + cancellable, error)) + return FALSE; + } + else if (repo_dir) + { + g_assert (dir_enum != NULL); + g_debug ("Adding: %s", gs_file_get_path_cached (child)); + if (!ostree_mutable_tree_replace_file (mtree, name, + ostree_repo_file_get_checksum ((OstreeRepoFile*) child), + error)) + return FALSE; + } + else + { + g_assert (dfd_iter != NULL); + g_auto(GLnxDirFdIterator) child_dfd_iter = { 0, }; + + if (!glnx_dirfd_iterator_init_at (dfd_iter->fd, name, FALSE, &child_dfd_iter, error)) + return FALSE; + + if (!write_dfd_iter_to_mtree_internal (self, &child_dfd_iter, child_mtree, + modifier, path, + cancellable, error)) + return FALSE; + + if (delete_after_commit) + { + if (!glnx_unlinkat (dfd_iter->fd, name, AT_REMOVEDIR, error)) + return FALSE; + } + } + + g_ptr_array_remove_index (path, path->len - 1); + + return TRUE; +} + +/* Given either a dir_enum or a dfd_iter, writes a non-dir (regfile/symlink) to + * the mtree. + */ +static gboolean +write_content_to_mtree_internal (OstreeRepo *self, + OstreeRepoFile *repo_dir, + GFileEnumerator *dir_enum, + GLnxDirFdIterator *dfd_iter, + WriteDirContentFlags writeflags, + GFileInfo *child_info, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GPtrArray *path, + GCancellable *cancellable, + GError **error) +{ + g_assert (dir_enum != NULL || dfd_iter != NULL); + + GFileType file_type = g_file_info_get_file_type (child_info); + const char *name = g_file_info_get_name (child_info); + + /* Load flags into boolean constants for ease of readability (we also need to + * NULL-check modifier) + */ + const gboolean canonical_permissions = modifier && + (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS); + const gboolean devino_canonical = modifier && + (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_DEVINO_CANONICAL); + /* We currently only honor the CONSUME flag in the dfd_iter case to avoid even + * more complexity in this function, and it'd mostly only be useful when + * operating on local filesystems anyways. + */ + const gboolean delete_after_commit = dfd_iter && modifier && + (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME); + + /* See if we have a devino hit; this is used below in a few places. */ + const char *loose_checksum = NULL; + if (dfd_iter != NULL) + { + guint32 dev = g_file_info_get_attribute_uint32 (child_info, "unix::device"); + guint64 inode = g_file_info_get_attribute_uint64 (child_info, "unix::inode"); + loose_checksum = devino_cache_lookup (self, modifier, dev, inode); + if (loose_checksum && devino_canonical) + { + /* Go directly to checksum, do not pass Go, do not collect $200. + * In this mode the app is required to break hardlinks for any + * files it wants to modify. + */ + if (!ostree_mutable_tree_replace_file (mtree, name, loose_checksum, error)) + return FALSE; + if (delete_after_commit) + { + if (!glnx_shutil_rm_rf_at (dfd_iter->fd, name, cancellable, error)) + return FALSE; + } + g_mutex_lock (&self->txn_lock); + self->txn.stats.devino_cache_hits++; + g_mutex_unlock (&self->txn_lock); + return TRUE; /* Early return */ + } + } + + /* Build the full path which we need for callbacks */ + g_ptr_array_add (path, (char*)name); + g_autofree char *child_relpath = ptrarray_path_join (path); + + /* For bare-user repos we'll reload our file info from the object + * (specifically the ostreemeta xattr), if it was checked out that way (via + * hardlink). The on-disk state is not normally what we want to commit. + * Basically we're making sure that we pick up "real" uid/gid and any xattrs + * there. + */ + g_autoptr(GVariant) source_xattrs = NULL; + g_autoptr(GFileInfo) source_child_info = NULL; + if (loose_checksum && self->mode == OSTREE_REPO_MODE_BARE_USER) + { + if (!ostree_repo_load_file (self, loose_checksum, NULL, &source_child_info, &source_xattrs, + cancellable, error)) + return FALSE; + child_info = source_child_info; + } + + /* Call the filter */ + g_autoptr(GFileInfo) modified_info = NULL; + OstreeRepoCommitFilterResult filter_result = + _ostree_repo_commit_modifier_apply (self, modifier, child_relpath, child_info, &modified_info); + const gboolean child_info_was_modified = !_ostree_gfileinfo_equal (child_info, modified_info); + + if (filter_result != OSTREE_REPO_COMMIT_FILTER_ALLOW) + { + g_ptr_array_remove_index (path, path->len - 1); + if (delete_after_commit) + { + g_assert (dfd_iter); + if (!glnx_shutil_rm_rf_at (dfd_iter->fd, name, cancellable, error)) + return FALSE; + } + /* Note: early return */ + return TRUE; + } + + switch (file_type) + { + case G_FILE_TYPE_SYMBOLIC_LINK: + case G_FILE_TYPE_REGULAR: + break; + default: + return glnx_throw (error, "Unsupported file type for file: '%s'", child_relpath); + } + + g_autoptr(GFile) child = NULL; + if (dir_enum != NULL) + child = g_file_enumerator_get_child (dir_enum, child_info); + + /* Our filters have passed, etc.; now we prepare to write the content object */ + glnx_autofd int file_input_fd = -1; + + /* Open the file now, since it's better for reading xattrs + * rather than using the /proc/self/fd links. + * + * TODO: Do this lazily, since for e.g. bare-user-only repos + * we don't have xattrs and don't need to open every file + * for things that have devino cache hits. + */ + if (file_type == G_FILE_TYPE_REGULAR && dfd_iter != NULL) + { + if (!glnx_openat_rdonly (dfd_iter->fd, name, FALSE, &file_input_fd, error)) + return FALSE; + } + + g_autoptr(GVariant) xattrs = NULL; + gboolean xattrs_were_modified; + if (dir_enum != NULL) + { + if (!get_final_xattrs (self, modifier, child_relpath, child_info, child, + -1, name, source_xattrs, &xattrs, &xattrs_were_modified, + cancellable, error)) + return FALSE; + } + else + { + /* These contortions are basically so we use glnx_fd_get_all_xattrs() + * for regfiles, and glnx_dfd_name_get_all_xattrs() for symlinks. + */ + int xattr_fd_arg = (file_input_fd != -1) ? file_input_fd : dfd_iter->fd; + const char *xattr_path_arg = (file_input_fd != -1) ? NULL : name; + if (!get_final_xattrs (self, modifier, child_relpath, child_info, child, + xattr_fd_arg, xattr_path_arg, source_xattrs, + &xattrs, &xattrs_were_modified, + cancellable, error)) + return FALSE; + } + + /* Used below to see whether we can do a fast path commit */ + const gboolean modified_file_meta = child_info_was_modified || xattrs_were_modified; + + /* A big prerequisite list of conditions for whether or not we can + * "adopt", i.e. just checksum and rename() into place + */ + const gboolean can_adopt_basic = + file_type == G_FILE_TYPE_REGULAR + && dfd_iter != NULL + && delete_after_commit + && ((writeflags & WRITE_DIR_CONTENT_FLAGS_CAN_ADOPT) > 0); + gboolean can_adopt = can_adopt_basic; + /* If basic prerquisites are met, check repo mode specific ones */ + if (can_adopt) + { + /* For bare repos, we could actually chown/reset the xattrs, but let's + * do the basic optimizations here first. + */ + if (self->mode == OSTREE_REPO_MODE_BARE) + can_adopt = !modified_file_meta; + else if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) + can_adopt = canonical_permissions; + else + /* This covers bare-user and archive. See comments in adopt_and_commit_regfile() + * for notes on adding bare-user later here. + */ + can_adopt = FALSE; + } + gboolean did_adopt = FALSE; + + /* The very fast path - we have a devino cache hit, nothing to write */ + if (loose_checksum && !modified_file_meta) + { + if (!ostree_mutable_tree_replace_file (mtree, name, loose_checksum, + error)) + return FALSE; + + g_mutex_lock (&self->txn_lock); + self->txn.stats.devino_cache_hits++; + g_mutex_unlock (&self->txn_lock); + } + /* Next fast path - we can "adopt" the file */ + else if (can_adopt) + { + char checksum[OSTREE_SHA256_STRING_LEN+1]; + if (!adopt_and_commit_regfile (self, dfd_iter->fd, name, modified_info, xattrs, + checksum, cancellable, error)) + return FALSE; + if (!ostree_mutable_tree_replace_file (mtree, name, checksum, error)) + return FALSE; + did_adopt = TRUE; + } + else + { + g_autoptr(GInputStream) file_input = NULL; + + if (file_type == G_FILE_TYPE_REGULAR) + { + if (dir_enum != NULL) + { + g_assert (child != NULL); + file_input = (GInputStream*)g_file_read (child, cancellable, error); + if (!file_input) + return FALSE; + } + else + { + /* We already opened the fd above */ + file_input = g_unix_input_stream_new (file_input_fd, FALSE); + } + } + + g_autofree guchar *child_file_csum = NULL; + if (!write_content_object (self, NULL, file_input, modified_info, xattrs, + &child_file_csum, cancellable, error)) + return FALSE; + + char tmp_checksum[OSTREE_SHA256_STRING_LEN+1]; + ostree_checksum_inplace_from_bytes (child_file_csum, tmp_checksum); + if (!ostree_mutable_tree_replace_file (mtree, name, tmp_checksum, + error)) + return FALSE; + } + + /* Process delete_after_commit. In the adoption case though, we already + * took ownership of the file above, usually via a renameat(). + */ + if (delete_after_commit && !did_adopt) + { + if (!glnx_unlinkat (dfd_iter->fd, name, 0, error)) + return FALSE; + } + + g_ptr_array_remove_index (path, path->len - 1); + + return TRUE; +} + +/* Handles the dirmeta for the given GFile dir and then calls + * write_{dir_entry,content}_to_mtree_internal() for each directory entry. */ +static gboolean +write_directory_to_mtree_internal (OstreeRepo *self, + GFile *dir, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GPtrArray *path, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoCommitFilterResult filter_result; + OstreeRepoFile *repo_dir = NULL; + + if (dir) + g_debug ("Examining: %s", gs_file_get_path_cached (dir)); + + /* If the directory is already in the repository, we can try to + * reuse checksums to skip checksumming. */ + if (dir && OSTREE_IS_REPO_FILE (dir) && modifier == NULL) + repo_dir = (OstreeRepoFile *) dir; + + if (repo_dir) + { + if (!ostree_repo_file_ensure_resolved (repo_dir, error)) + return FALSE; + + /* ostree_mutable_tree_fill_from_dirtree returns FALSE if mtree isn't + * empty: in which case we're responsible for merging the trees. */ + if (ostree_mutable_tree_fill_empty_from_dirtree (mtree, + ostree_repo_file_get_repo (repo_dir), + ostree_repo_file_tree_get_contents_checksum (repo_dir), + ostree_repo_file_get_checksum (repo_dir))) + return TRUE; + + ostree_mutable_tree_set_metadata_checksum (mtree, ostree_repo_file_tree_get_metadata_checksum (repo_dir)); + + filter_result = OSTREE_REPO_COMMIT_FILTER_ALLOW; + } + else + { + g_autoptr(GVariant) xattrs = NULL; + + g_autoptr(GFileInfo) child_info = + g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!child_info) + return FALSE; + + g_autofree char *relpath = NULL; + if (modifier != NULL) + relpath = ptrarray_path_join (path); + + g_autoptr(GFileInfo) modified_info = NULL; + filter_result = _ostree_repo_commit_modifier_apply (self, modifier, relpath, child_info, &modified_info); + + if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW) + { + if (!get_final_xattrs (self, modifier, relpath, child_info, dir, -1, NULL, + NULL, &xattrs, NULL, cancellable, error)) + return FALSE; + + g_autofree guchar *child_file_csum = NULL; + if (!_ostree_repo_write_directory_meta (self, modified_info, xattrs, &child_file_csum, + cancellable, error)) + return FALSE; + + g_autofree char *tmp_checksum = ostree_checksum_from_bytes (child_file_csum); + ostree_mutable_tree_set_metadata_checksum (mtree, tmp_checksum); + } + } + + if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW) + { + g_autoptr(GFileEnumerator) dir_enum = NULL; + + dir_enum = g_file_enumerate_children ((GFile*)dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, + error); + if (!dir_enum) + return FALSE; + + while (TRUE) + { + GFileInfo *child_info; + + if (!g_file_enumerator_iterate (dir_enum, &child_info, NULL, + cancellable, error)) + return FALSE; + if (child_info == NULL) + break; + + if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY) + { + if (!write_dir_entry_to_mtree_internal (self, repo_dir, dir_enum, NULL, + WRITE_DIR_CONTENT_FLAGS_NONE, + child_info, + mtree, modifier, path, + cancellable, error)) + return FALSE; + } + else + { + if (!write_content_to_mtree_internal (self, repo_dir, dir_enum, NULL, + WRITE_DIR_CONTENT_FLAGS_NONE, + child_info, + mtree, modifier, path, + cancellable, error)) + return FALSE; + } + } + } + + return TRUE; +} + +/* Handles the dirmeta for the dir described by src_dfd_iter and then calls + * write_{dir_entry,content}_to_mtree_internal() for each directory entry. */ +static gboolean +write_dfd_iter_to_mtree_internal (OstreeRepo *self, + GLnxDirFdIterator *src_dfd_iter, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GPtrArray *path, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GFileInfo) child_info = NULL; + g_autoptr(GFileInfo) modified_info = NULL; + g_autoptr(GVariant) xattrs = NULL; + g_autofree guchar *child_file_csum = NULL; + g_autofree char *tmp_checksum = NULL; + g_autofree char *relpath = NULL; + OstreeRepoCommitFilterResult filter_result; + struct stat dir_stbuf; + + if (!glnx_fstat (src_dfd_iter->fd, &dir_stbuf, error)) + return FALSE; + + child_info = _ostree_stbuf_to_gfileinfo (&dir_stbuf); + + if (modifier != NULL) + { + relpath = ptrarray_path_join (path); + + filter_result = _ostree_repo_commit_modifier_apply (self, modifier, relpath, child_info, &modified_info); + } + else + { + filter_result = OSTREE_REPO_COMMIT_FILTER_ALLOW; + modified_info = g_object_ref (child_info); + } + + if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW) + { + if (!get_final_xattrs (self, modifier, relpath, modified_info, NULL, src_dfd_iter->fd, + NULL, NULL, &xattrs, NULL, cancellable, error)) + return FALSE; + + if (!_ostree_repo_write_directory_meta (self, modified_info, xattrs, &child_file_csum, + cancellable, error)) + return FALSE; + + g_free (tmp_checksum); + tmp_checksum = ostree_checksum_from_bytes (child_file_csum); + ostree_mutable_tree_set_metadata_checksum (mtree, tmp_checksum); + } + + if (filter_result != OSTREE_REPO_COMMIT_FILTER_ALLOW) + { + /* Note - early return */ + return TRUE; + } + + /* See if this dir is on the same device; if so we can adopt (if enabled) */ + WriteDirContentFlags flags = 0; + if (dir_stbuf.st_dev == self->device) + flags |= WRITE_DIR_CONTENT_FLAGS_CAN_ADOPT; + + while (TRUE) + { + struct dirent *dent; + if (!glnx_dirfd_iterator_next_dent (src_dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + struct stat stbuf; + if (!glnx_fstatat (src_dfd_iter->fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + g_autoptr(GFileInfo) child_info = _ostree_stbuf_to_gfileinfo (&stbuf); + g_file_info_set_name (child_info, dent->d_name); + + if (S_ISDIR (stbuf.st_mode)) + { + if (!write_dir_entry_to_mtree_internal (self, NULL, NULL, src_dfd_iter, + flags, child_info, + mtree, modifier, path, + cancellable, error)) + return FALSE; + + /* We handled the dir, move onto the next */ + continue; + } + + if (S_ISREG (stbuf.st_mode)) + ; + else if (S_ISLNK (stbuf.st_mode)) + { + if (!ot_readlinkat_gfile_info (src_dfd_iter->fd, dent->d_name, + child_info, cancellable, error)) + return FALSE; + } + else + { + return glnx_throw (error, "Not a regular file or symlink: %s", + dent->d_name); + } + + /* Write a content object, we handled directories above */ + if (!write_content_to_mtree_internal (self, NULL, NULL, src_dfd_iter, + flags, child_info, + mtree, modifier, path, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_repo_write_directory_to_mtree: + * @self: Repo + * @dir: Path to a directory + * @mtree: Overlay directory contents into this tree + * @modifier: (allow-none): Optional modifier + * @cancellable: Cancellable + * @error: Error + * + * Store objects for @dir and all children into the repository @self, + * overlaying the resulting filesystem hierarchy into @mtree. + */ +gboolean +ostree_repo_write_directory_to_mtree (OstreeRepo *self, + GFile *dir, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GCancellable *cancellable, + GError **error) +{ + + /* Short cut local files */ + if (g_file_is_native (dir)) + { + if (!ostree_repo_write_dfd_to_mtree (self, AT_FDCWD, gs_file_get_path_cached (dir), + mtree, modifier, cancellable, error)) + return FALSE; + } + else + { + _ostree_repo_setup_generate_sizes (self, modifier); + + g_autoptr(GPtrArray) path = g_ptr_array_new (); + if (!write_directory_to_mtree_internal (self, dir, mtree, modifier, path, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_repo_write_dfd_to_mtree: + * @self: Repo + * @dfd: Directory file descriptor + * @path: Path + * @mtree: Overlay directory contents into this tree + * @modifier: (allow-none): Optional modifier + * @cancellable: Cancellable + * @error: Error + * + * Store as objects all contents of the directory referred to by @dfd + * and @path all children into the repository @self, overlaying the + * resulting filesystem hierarchy into @mtree. + */ +gboolean +ostree_repo_write_dfd_to_mtree (OstreeRepo *self, + int dfd, + const char *path, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GCancellable *cancellable, + GError **error) +{ + _ostree_repo_setup_generate_sizes (self, modifier); + + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_at (dfd, path, FALSE, &dfd_iter, error)) + return FALSE; + + g_autoptr(GPtrArray) pathbuilder = g_ptr_array_new (); + if (!write_dfd_iter_to_mtree_internal (self, &dfd_iter, mtree, modifier, pathbuilder, + cancellable, error)) + return FALSE; + + /* And now finally remove the toplevel; see also the handling for this flag in + * the write_dfd_iter_to_mtree_internal() function. As a special case we don't + * try to remove `.` (since we'd get EINVAL); that's what's used in + * rpm-ostree. + */ + const gboolean delete_after_commit = modifier && + (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME); + if (delete_after_commit && !g_str_equal (path, ".")) + { + if (!glnx_unlinkat (dfd, path, AT_REMOVEDIR, error)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_repo_write_mtree: + * @self: Repo + * @mtree: Mutable tree + * @out_file: (out): An #OstreeRepoFile representing @mtree's root. + * @cancellable: Cancellable + * @error: Error + * + * Write all metadata objects for @mtree to repo; the resulting + * @out_file points to the %OSTREE_OBJECT_TYPE_DIR_TREE object that + * the @mtree represented. + */ +gboolean +ostree_repo_write_mtree (OstreeRepo *self, + OstreeMutableTree *mtree, + GFile **out_file, + GCancellable *cancellable, + GError **error) +{ + const char *contents_checksum, *metadata_checksum; + g_autoptr(GFile) ret_file = NULL; + + if (!ostree_mutable_tree_check_error (mtree, error)) + return glnx_prefix_error (error, "mtree"); + + metadata_checksum = ostree_mutable_tree_get_metadata_checksum (mtree); + if (!metadata_checksum) + return glnx_throw (error, "Can't commit an empty tree"); + + contents_checksum = ostree_mutable_tree_get_contents_checksum (mtree); + if (contents_checksum) + { + ret_file = G_FILE (_ostree_repo_file_new_root (self, contents_checksum, metadata_checksum)); + } + else + { + g_autoptr(GHashTable) dir_metadata_checksums = NULL; + g_autoptr(GHashTable) dir_contents_checksums = NULL; + g_autoptr(GVariant) serialized_tree = NULL; + g_autofree guchar *contents_csum = NULL; + char contents_checksum_buf[OSTREE_SHA256_STRING_LEN+1]; + + dir_contents_checksums = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, (GDestroyNotify)g_free); + dir_metadata_checksums = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, (GDestroyNotify)g_free); + + GLNX_HASH_TABLE_FOREACH_KV (ostree_mutable_tree_get_subdirs (mtree), + const char*, name, OstreeMutableTree*, child_dir) + { + g_autoptr(GFile) child_file = NULL; + if (!ostree_repo_write_mtree (self, child_dir, &child_file, + cancellable, error)) + return FALSE; + + g_hash_table_replace (dir_contents_checksums, g_strdup (name), + g_strdup (ostree_repo_file_tree_get_contents_checksum (OSTREE_REPO_FILE (child_file)))); + g_hash_table_replace (dir_metadata_checksums, g_strdup (name), + g_strdup (ostree_repo_file_tree_get_metadata_checksum (OSTREE_REPO_FILE (child_file)))); + } + + serialized_tree = create_tree_variant_from_hashes (ostree_mutable_tree_get_files (mtree), + dir_contents_checksums, + dir_metadata_checksums); + + if (!ostree_repo_write_metadata (self, OSTREE_OBJECT_TYPE_DIR_TREE, NULL, + serialized_tree, &contents_csum, + cancellable, error)) + return FALSE; + + ostree_checksum_inplace_from_bytes (contents_csum, contents_checksum_buf); + ostree_mutable_tree_set_contents_checksum (mtree, contents_checksum_buf); + + ret_file = G_FILE (_ostree_repo_file_new_root (self, contents_checksum_buf, metadata_checksum)); + } + + if (out_file) + *out_file = g_steal_pointer (&ret_file); + return TRUE; +} + +/** + * ostree_repo_commit_modifier_new: + * @flags: Control options for filter + * @commit_filter: (allow-none): Function that can inspect individual files + * @user_data: (allow-none): User data + * @destroy_notify: A #GDestroyNotify + * + * Returns: (transfer full): A new commit modifier. + */ +OstreeRepoCommitModifier * +ostree_repo_commit_modifier_new (OstreeRepoCommitModifierFlags flags, + OstreeRepoCommitFilter commit_filter, + gpointer user_data, + GDestroyNotify destroy_notify) +{ + OstreeRepoCommitModifier *modifier = g_new0 (OstreeRepoCommitModifier, 1); + + modifier->refcount = 1; + modifier->flags = flags; + modifier->filter = commit_filter; + modifier->user_data = user_data; + modifier->destroy_notify = destroy_notify; + + return modifier; +} + +OstreeRepoCommitModifier * +ostree_repo_commit_modifier_ref (OstreeRepoCommitModifier *modifier) +{ + gint refcount = g_atomic_int_add (&modifier->refcount, 1); + g_assert (refcount > 0); + return modifier; +} + +void +ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier) +{ + if (!modifier) + return; + if (!g_atomic_int_dec_and_test (&modifier->refcount)) + return; + + if (modifier->destroy_notify) + modifier->destroy_notify (modifier->user_data); + + if (modifier->xattr_destroy) + modifier->xattr_destroy (modifier->xattr_user_data); + + g_clear_pointer (&modifier->devino_cache, (GDestroyNotify)g_hash_table_unref); + + g_clear_object (&modifier->sepolicy); + (void) glnx_tmpdir_delete (&modifier->sepolicy_tmpdir, NULL, NULL); + + g_free (modifier); + return; +} + +/** + * ostree_repo_commit_modifier_set_xattr_callback: + * @modifier: An #OstreeRepoCommitModifier + * @callback: Function to be invoked, should return extended attributes for path + * @destroy: Destroy notification + * @user_data: Data for @callback: + * + * If set, this function should return extended attributes to use for + * the given path. This is useful for things like ACLs and SELinux, + * where a build system can label the files as it's committing to the + * repository. + */ +void +ostree_repo_commit_modifier_set_xattr_callback (OstreeRepoCommitModifier *modifier, + OstreeRepoCommitModifierXattrCallback callback, + GDestroyNotify destroy, + gpointer user_data) +{ + modifier->xattr_callback = callback; + modifier->xattr_destroy = destroy; + modifier->xattr_user_data = user_data; +} + +/** + * ostree_repo_commit_modifier_set_sepolicy: + * @modifier: An #OstreeRepoCommitModifier + * @sepolicy: (allow-none): Policy to use for labeling + * + * If @policy is non-%NULL, use it to look up labels to use for + * "security.selinux" extended attributes. + * + * Note that any policy specified this way operates in addition to any + * extended attributes provided via + * ostree_repo_commit_modifier_set_xattr_callback(). However if both + * specify a value for "security.selinux", then the one from the + * policy wins. + */ +void +ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier *modifier, + OstreeSePolicy *sepolicy) +{ + g_clear_object (&modifier->sepolicy); + modifier->sepolicy = sepolicy ? g_object_ref (sepolicy) : NULL; +} + +/** + * ostree_repo_commit_modifier_set_sepolicy_from_commit: + * @modifier: Commit modifier + * @repo: OSTree repo containing @rev + * @rev: Find SELinux policy from this base commit + * @cancellable: + * @error: + * + * In many cases, one wants to create a "derived" commit from base commit. + * SELinux policy labels are part of that base commit. This API allows + * one to easily set up SELinux labeling from a base commit. + */ +gboolean +ostree_repo_commit_modifier_set_sepolicy_from_commit (OstreeRepoCommitModifier *modifier, + OstreeRepo *repo, + const char *rev, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("setting sepolicy from commit", error); + g_autofree char *commit = NULL; + g_autoptr(GFile) root = NULL; + if (!ostree_repo_read_commit (repo, rev, &root, &commit, cancellable, error)) + return FALSE; + const char policypath[] = "usr/etc/selinux"; + g_autoptr(GFile) policyroot = g_file_get_child (root, policypath); + if (!g_file_query_exists (policyroot, NULL)) + return TRUE; /* No policy, nothing to do */ + + GLnxTmpDir tmpdir = {0,}; + if (!glnx_mkdtemp ("ostree-commit-sepolicy-XXXXXX", 0700, &tmpdir, error)) + return FALSE; + if (!glnx_shutil_mkdir_p_at (tmpdir.fd, "usr/etc", 0755, cancellable, error)) + return FALSE; + + OstreeRepoCheckoutAtOptions coopts = {0,}; + coopts.mode = OSTREE_REPO_CHECKOUT_MODE_USER; + coopts.subpath = glnx_strjoina ("/", policypath); + + if (!ostree_repo_checkout_at (repo, &coopts, tmpdir.fd, policypath, commit, cancellable, error)) + return glnx_prefix_error (error, "policy checkout"); + + g_autoptr(OstreeSePolicy) policy = ostree_sepolicy_new_at (tmpdir.fd, cancellable, error); + if (!policy) + return glnx_prefix_error (error, "reading policy"); + + ostree_repo_commit_modifier_set_sepolicy (modifier, policy); + /* Transfer ownership */ + modifier->sepolicy_tmpdir = tmpdir; + tmpdir.initialized = FALSE; + + return TRUE; +} + +/** + * ostree_repo_commit_modifier_set_devino_cache: + * @modifier: Modifier + * @cache: A hash table caching device,inode to checksums + * + * See the documentation for + * `ostree_repo_devino_cache_new()`. This function can + * then be used for later calls to + * `ostree_repo_write_directory_to_mtree()` to optimize commits. + * + * Note if your process has multiple writers, you should use separate + * `OSTreeRepo` instances if you want to also use this API. + * + * This function will add a reference to @cache without copying - you + * should avoid further mutation of the cache. + * + * Since: 2017.13 + */ +void +ostree_repo_commit_modifier_set_devino_cache (OstreeRepoCommitModifier *modifier, + OstreeRepoDevInoCache *cache) +{ + modifier->devino_cache = g_hash_table_ref ((GHashTable*)cache); +} + +OstreeRepoDevInoCache * +ostree_repo_devino_cache_ref (OstreeRepoDevInoCache *cache) +{ + g_hash_table_ref ((GHashTable*)cache); + return cache; +} + +void +ostree_repo_devino_cache_unref (OstreeRepoDevInoCache *cache) +{ + g_hash_table_unref ((GHashTable*)cache); +} + +G_DEFINE_BOXED_TYPE(OstreeRepoDevInoCache, ostree_repo_devino_cache, + ostree_repo_devino_cache_ref, + ostree_repo_devino_cache_unref); + +G_DEFINE_BOXED_TYPE(OstreeRepoCommitModifier, ostree_repo_commit_modifier, + ostree_repo_commit_modifier_ref, + ostree_repo_commit_modifier_unref); + +/* Special case between bare-user and bare-user-only, + * mostly for https://github.com/flatpak/flatpak/issues/845 + * see below for any more comments. + */ +static gboolean +import_is_bareuser_only_conversion (OstreeRepo *src_repo, + OstreeRepo *dest_repo, + OstreeObjectType objtype) +{ + return src_repo->mode == OSTREE_REPO_MODE_BARE_USER + && dest_repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY + && objtype == OSTREE_OBJECT_TYPE_FILE; +} + +/* Returns TRUE if we can potentially just call link() to copy an object; + * if untrusted the repos must be owned by the same uid. + */ +static gboolean +import_via_reflink_is_possible (OstreeRepo *src_repo, + OstreeRepo *dest_repo, + OstreeObjectType objtype, + gboolean trusted) +{ + /* Untrusted pulls require matching ownership */ + if (!trusted && (src_repo->owner_uid != dest_repo->owner_uid)) + return FALSE; + /* Equal modes are always compatible, and metadata + * is identical between all modes. + */ + if (src_repo->mode == dest_repo->mode || + OSTREE_OBJECT_TYPE_IS_META (objtype)) + return TRUE; + /* And now a special case between bare-user and bare-user-only, + * mostly for https://github.com/flatpak/flatpak/issues/845 + */ + if (import_is_bareuser_only_conversion (src_repo, dest_repo, objtype)) + return TRUE; + return FALSE; +} + +/* Copy the detached metadata for commit @checksum from @source repo + * to @self. + */ +static gboolean +copy_detached_metadata (OstreeRepo *self, + OstreeRepo *source, + const char *checksum, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) detached_meta = NULL; + if (!ostree_repo_read_commit_detached_metadata (source, + checksum, &detached_meta, + cancellable, error)) + return FALSE; + + if (detached_meta) + { + if (!ostree_repo_write_commit_detached_metadata (self, + checksum, detached_meta, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/* Try to import an object via reflink or just linkat(); returns a value in + * @out_was_supported if we were able to do it or not. In this path + * we're not verifying the checksum. + */ +static gboolean +import_one_object_direct (OstreeRepo *dest_repo, + OstreeRepo *src_repo, + const char *checksum, + OstreeObjectType objtype, + gboolean *out_was_supported, + GCancellable *cancellable, + GError **error) +{ + const char *errprefix = glnx_strjoina ("Importing ", checksum, ".", + ostree_object_type_to_string (objtype)); + GLNX_AUTO_PREFIX_ERROR (errprefix, error); + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (loose_path_buf, checksum, objtype, dest_repo->mode); + + /* hardlinks require the owner to match and to be on the same device */ + const gboolean can_hardlink = + src_repo->owner_uid == dest_repo->owner_uid && + src_repo->device == dest_repo->device; + + /* Find our target dfd */ + int dest_dfd; + if (dest_repo->commit_stagedir.initialized) + dest_dfd = dest_repo->commit_stagedir.fd; + else + dest_dfd = dest_repo->objects_dir_fd; + + if (!_ostree_repo_ensure_loose_objdir_at (dest_dfd, loose_path_buf, cancellable, error)) + return FALSE; + + gboolean did_hardlink = FALSE; + if (can_hardlink) + { + if (linkat (src_repo->objects_dir_fd, loose_path_buf, dest_dfd, loose_path_buf, 0) != 0) + { + if (errno == EEXIST) + did_hardlink = TRUE; + else if (errno == EMLINK || errno == EXDEV || errno == EPERM) + { + /* EMLINK, EXDEV and EPERM shouldn't be fatal; we just can't do + * the optimization of hardlinking instead of copying. Fall + * through below. + */ + } + else + return glnx_throw_errno_prefix (error, "linkat"); + } + else + did_hardlink = TRUE; + } + + /* If we weren't able to hardlink, fall back to a copy (which might be + * reflinked). + */ + if (!did_hardlink) + { + struct stat stbuf; + + if (!glnx_fstatat (src_repo->objects_dir_fd, loose_path_buf, + &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + /* Let's punt for symlinks right now, it's more complicated */ + if (!S_ISREG (stbuf.st_mode)) + { + *out_was_supported = FALSE; + return TRUE; + } + + /* This is yet another variation of glnx_file_copy_at() + * that basically just optionally does chown(). Perhaps + * in the future we should add flags for those things? + */ + glnx_autofd int src_fd = -1; + if (!glnx_openat_rdonly (src_repo->objects_dir_fd, loose_path_buf, + FALSE, &src_fd, error)) + return FALSE; + + /* Open a tmpfile for dest */ + g_auto(GLnxTmpfile) tmp_dest = { 0, }; + if (!glnx_open_tmpfile_linkable_at (dest_dfd, ".", O_WRONLY | O_CLOEXEC, + &tmp_dest, error)) + return FALSE; + + if (glnx_regfile_copy_bytes (src_fd, tmp_dest.fd, (off_t) -1) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); + + /* Only chown for true bare repos */ + if (dest_repo->mode == OSTREE_REPO_MODE_BARE) + { + if (fchown (tmp_dest.fd, stbuf.st_uid, stbuf.st_gid) != 0) + return glnx_throw_errno_prefix (error, "fchown"); + } + + /* Don't want to copy xattrs for archive repos, nor for + * bare-user-only. We also only do this for content + * objects. + */ + const gboolean src_is_bare_or_bare_user = + G_IN_SET (src_repo->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER); + if (src_is_bare_or_bare_user && !OSTREE_OBJECT_TYPE_IS_META(objtype)) + { + if (src_repo->mode == OSTREE_REPO_MODE_BARE) + { + g_autoptr(GVariant) xattrs = NULL; + if (!glnx_fd_get_all_xattrs (src_fd, &xattrs, + cancellable, error)) + return FALSE; + if (!glnx_fd_set_all_xattrs (tmp_dest.fd, xattrs, + cancellable, error)) + return FALSE; + } + else if (dest_repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) + { + /* Nothing; this is the "bareuser-only conversion case", + * we don't need to set any xattrs in the dest repo. + */ + } + else + { + /* And this case must be bare-user → bare-user */ + g_assert (src_repo->mode == OSTREE_REPO_MODE_BARE_USER); + g_assert (src_repo->mode == dest_repo->mode); + + /* bare-user; we just want ostree.usermeta */ + g_autoptr(GBytes) bytes = + glnx_fgetxattr_bytes (src_fd, "user.ostreemeta", error); + if (bytes == NULL) + return FALSE; + + if (TEMP_FAILURE_RETRY (fsetxattr (tmp_dest.fd, "user.ostreemeta", + (char*)g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes), 0)) != 0) + return glnx_throw_errno_prefix (error, "fsetxattr"); + } + } + + if (fchmod (tmp_dest.fd, stbuf.st_mode & ~S_IFMT) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + /* For archive repos, we just let the timestamps be object creation. + * Otherwise, copy the ostree timestamp value. + */ + if (_ostree_repo_mode_is_bare (dest_repo->mode)) + { + struct timespec ts[2]; + ts[0] = stbuf.st_atim; + ts[1] = stbuf.st_mtim; + (void) futimens (tmp_dest.fd, ts); + } + + if (!_ostree_repo_commit_tmpf_final (dest_repo, checksum, objtype, + &tmp_dest, cancellable, error)) + return FALSE; + } + + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + if (!copy_detached_metadata (dest_repo, src_repo, checksum, cancellable, error)) + return FALSE; + } + else if (objtype == OSTREE_OBJECT_TYPE_FILE) + { + if (!_import_payload_link (dest_repo, src_repo, checksum, cancellable, error)) + return FALSE; + } + *out_was_supported = TRUE; + return TRUE; +} + +/* A version of ostree_repo_import_object_from_with_trust() + * with flags; may make this public API later. + */ +gboolean +_ostree_repo_import_object (OstreeRepo *self, + OstreeRepo *source, + OstreeObjectType objtype, + const char *checksum, + OstreeRepoImportFlags flags, + GCancellable *cancellable, + GError **error) +{ + const gboolean trusted = (flags & _OSTREE_REPO_IMPORT_FLAGS_TRUSTED) > 0; + /* Implements OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES which was designed for flatpak */ + const gboolean verify_bareuseronly = (flags & _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY) > 0; + /* A special case between bare-user and bare-user-only, + * mostly for https://github.com/flatpak/flatpak/issues/845 + */ + const gboolean is_bareuseronly_conversion = + import_is_bareuser_only_conversion (source, self, objtype); + gboolean try_direct = TRUE; + + /* If we need to do bareuseronly verification, or we're potentially doing a + * bareuseronly conversion, let's verify those first so we don't complicate + * the rest of the code below. + */ + if ((verify_bareuseronly || is_bareuseronly_conversion) && !OSTREE_OBJECT_TYPE_IS_META (objtype)) + { + g_autoptr(GFileInfo) src_finfo = NULL; + if (!ostree_repo_load_file (source, checksum, + NULL, &src_finfo, NULL, + cancellable, error)) + return FALSE; + + if (verify_bareuseronly) + { + if (!_ostree_validate_bareuseronly_mode_finfo (src_finfo, checksum, error)) + return FALSE; + } + + if (is_bareuseronly_conversion) + { + switch (g_file_info_get_file_type (src_finfo)) + { + case G_FILE_TYPE_REGULAR: + /* This is OK, we'll try a hardlink */ + break; + case G_FILE_TYPE_SYMBOLIC_LINK: + /* Symlinks in bare-user are regular files, we can't + * hardlink them to another repo mode. + */ + try_direct = FALSE; + break; + default: + g_assert_not_reached (); + break; + } + } + } + + /* First, let's see if we can import via reflink/hardlink. */ + if (try_direct && import_via_reflink_is_possible (source, self, objtype, trusted)) + { + /* For local repositories, if the untrusted flag is set, we verify the + * checksum first. This assumes then that the files are immutable - the + * above check verified that the owner uids match. + */ + if (!trusted) + { + if (!ostree_repo_fsck_object (source, objtype, checksum, + cancellable, error)) + return FALSE; + } + + gboolean direct_was_supported = FALSE; + if (!import_one_object_direct (self, source, checksum, objtype, + &direct_was_supported, + cancellable, error)) + return FALSE; + + /* If direct import succeeded, we're done! */ + if (direct_was_supported) + return TRUE; + } + + /* The more expensive copy path; involves parsing the object. For + * example the input might be an archive repo and the destination bare, + * or vice versa. Or we may simply need to verify the checksum. + */ + + /* First, do we have the object already? */ + gboolean has_object; + if (!ostree_repo_has_object (self, objtype, checksum, &has_object, + cancellable, error)) + return FALSE; + /* If we have it, we're done */ + if (has_object) + { + if (objtype == OSTREE_OBJECT_TYPE_FILE) + { + if (!_import_payload_link (self, source, checksum, cancellable, error)) + return FALSE; + } + return TRUE; + } + + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + { + /* Metadata object */ + g_autoptr(GVariant) variant = NULL; + + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + /* FIXME - cleanup detached metadata if copy below fails */ + if (!copy_detached_metadata (self, source, checksum, cancellable, error)) + return FALSE; + } + + if (!ostree_repo_load_variant (source, objtype, checksum, + &variant, error)) + return FALSE; + + /* Note this one also now verifies structure in the !trusted case */ + g_autofree guchar *real_csum = NULL; + if (!ostree_repo_write_metadata (self, objtype, + checksum, variant, + trusted ? NULL : &real_csum, + cancellable, error)) + return FALSE; + } + else + { + /* Content object */ + guint64 length; + g_autoptr(GInputStream) object_stream = NULL; + + if (!ostree_repo_load_object_stream (source, objtype, checksum, + &object_stream, &length, + cancellable, error)) + return FALSE; + + g_autofree guchar *real_csum = NULL; + if (!ostree_repo_write_content (self, checksum, + object_stream, length, + trusted ? NULL : &real_csum, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +static OstreeRepoTransactionStats * +ostree_repo_transaction_stats_copy (OstreeRepoTransactionStats *stats) +{ + return g_memdup (stats, sizeof (OstreeRepoTransactionStats)); +} + +static void +ostree_repo_transaction_stats_free (OstreeRepoTransactionStats *stats) +{ + return g_free (stats); +} + +G_DEFINE_BOXED_TYPE(OstreeRepoTransactionStats, ostree_repo_transaction_stats, + ostree_repo_transaction_stats_copy, + ostree_repo_transaction_stats_free); diff --git a/src/libostree/ostree-repo-deprecated.h b/src/libostree/ostree-repo-deprecated.h new file mode 100644 index 0000000..1c9d225 --- /dev/null +++ b/src/libostree/ostree-repo-deprecated.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-core.h" +#include "ostree-types.h" + +#ifndef __GI_SCANNER__ +#ifndef G_GNUC_DEPRECATED_FOR +# define G_GNUC_DEPRECATED_FOR(x) +#endif +#endif + +G_BEGIN_DECLS + +/** + * OstreeRepoCheckoutOptions: (skip) + * + * An extensible options structure controlling checkout. Ensure that + * you have entirely zeroed the structure, then set just the desired + * options. This is used by ostree_repo_checkout_tree_at() which + * supercedes previous separate enumeration usage in + * ostree_repo_checkout_tree(). + */ +typedef struct { + OstreeRepoCheckoutMode mode; + OstreeRepoCheckoutOverwriteMode overwrite_mode; + + guint enable_uncompressed_cache : 1; + guint disable_fsync : 1; + guint process_whiteouts : 1; + guint no_copy_fallback : 1; + guint reserved : 28; + + const char *subpath; + + OstreeRepoDevInoCache *devino_to_csum_cache; + + guint unused_uints[6]; + gpointer unused_ptrs[7]; +} OstreeRepoCheckoutOptions; + +_OSTREE_PUBLIC +gboolean ostree_repo_checkout_tree_at (OstreeRepo *self, + OstreeRepoCheckoutOptions *options, + int destination_dfd, + const char *destination_path, + const char *commit, + GCancellable *cancellable, + GError **error) +G_GNUC_DEPRECATED_FOR(ostree_repo_checkout_at); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-file-enumerator.c b/src/libostree/ostree-repo-file-enumerator.c new file mode 100644 index 0000000..46d20ab --- /dev/null +++ b/src/libostree/ostree-repo-file-enumerator.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ostree-repo-file-enumerator.h" +#include + +struct _OstreeRepoFileEnumerator +{ + GFileEnumerator parent; + + OstreeRepoFile *dir; + char *attributes; + GFileQueryInfoFlags flags; + + int index; +}; + +#define ostree_repo_file_enumerator_get_type _ostree_repo_file_enumerator_get_type +G_DEFINE_TYPE (OstreeRepoFileEnumerator, ostree_repo_file_enumerator, G_TYPE_FILE_ENUMERATOR); + +static GFileInfo *ostree_repo_file_enumerator_next_file (GFileEnumerator *enumerator, + GCancellable *cancellable, + GError **error); +static gboolean ostree_repo_file_enumerator_close (GFileEnumerator *enumerator, + GCancellable *cancellable, + GError **error); + + +static void +ostree_repo_file_enumerator_dispose (GObject *object) +{ + OstreeRepoFileEnumerator *self; + + self = OSTREE_REPO_FILE_ENUMERATOR (object); + + g_clear_object (&self->dir); + g_free (self->attributes); + + if (G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->dispose) + G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->dispose (object); +} + +static void +ostree_repo_file_enumerator_finalize (GObject *object) +{ + OstreeRepoFileEnumerator *self; + + self = OSTREE_REPO_FILE_ENUMERATOR (object); + (void)self; + + G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->finalize (object); +} + + +static void +ostree_repo_file_enumerator_class_init (OstreeRepoFileEnumeratorClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass); + + gobject_class->finalize = ostree_repo_file_enumerator_finalize; + gobject_class->dispose = ostree_repo_file_enumerator_dispose; + + enumerator_class->next_file = ostree_repo_file_enumerator_next_file; + enumerator_class->close_fn = ostree_repo_file_enumerator_close; +} + +static void +ostree_repo_file_enumerator_init (OstreeRepoFileEnumerator *self) +{ +} + +GFileEnumerator * +_ostree_repo_file_enumerator_new (OstreeRepoFile *dir, + const char *attributes, + GFileQueryInfoFlags flags, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoFileEnumerator *self; + + self = g_object_new (OSTREE_TYPE_REPO_FILE_ENUMERATOR, + "container", dir, + NULL); + + self->dir = g_object_ref (dir); + self->attributes = g_strdup (attributes); + self->flags = flags; + + return G_FILE_ENUMERATOR (self); +} + +static GFileInfo * +ostree_repo_file_enumerator_next_file (GFileEnumerator *enumerator, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoFileEnumerator *self = OSTREE_REPO_FILE_ENUMERATOR (enumerator); + gboolean ret = FALSE; + GFileInfo *info = NULL; + + if (!ostree_repo_file_tree_query_child (self->dir, self->index, + self->attributes, self->flags, + &info, cancellable, error)) + goto out; + + self->index++; + + ret = TRUE; + out: + if (!ret) + g_clear_object (&info); + return info; +} + +static gboolean +ostree_repo_file_enumerator_close (GFileEnumerator *enumerator, + GCancellable *cancellable, + GError **error) +{ + return TRUE; +} diff --git a/src/libostree/ostree-repo-file-enumerator.h b/src/libostree/ostree-repo-file-enumerator.h new file mode 100644 index 0000000..e93295b --- /dev/null +++ b/src/libostree/ostree-repo-file-enumerator.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include "ostree-repo-file.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_REPO_FILE_ENUMERATOR (_ostree_repo_file_enumerator_get_type ()) +#define OSTREE_REPO_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumerator)) +#define OSTREE_REPO_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumeratorClass)) +#define OSTREE_IS_REPO_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR)) +#define OSTREE_IS_REPO_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_REPO_FILE_ENUMERATOR)) +#define OSTREE_REPO_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumeratorClass)) + +typedef struct _OstreeRepoFileEnumerator OstreeRepoFileEnumerator; +typedef struct _OstreeRepoFileEnumeratorClass OstreeRepoFileEnumeratorClass; + +struct _OstreeRepoFileEnumeratorClass +{ + GFileEnumeratorClass parent_class; +}; + +G_GNUC_INTERNAL +GType _ostree_repo_file_enumerator_get_type (void) G_GNUC_CONST; + +G_GNUC_INTERNAL +GFileEnumerator * _ostree_repo_file_enumerator_new (OstreeRepoFile *dir, + const char *attributes, + GFileQueryInfoFlags flags, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-file.c b/src/libostree/ostree-repo-file.c new file mode 100644 index 0000000..7ad1152 --- /dev/null +++ b/src/libostree/ostree-repo-file.c @@ -0,0 +1,1021 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "otutil.h" +#include "ostree-repo-file-enumerator.h" +#include "ostree-repo-private.h" + +static void ostree_repo_file_file_iface_init (GFileIface *iface); + +struct OstreeRepoFile +{ + GObject parent_instance; + + OstreeRepo *repo; + OstreeRepoFile *parent; + int index; + char *name; + + char *cached_file_checksum; + + char *tree_contents_checksum; + GVariant *tree_contents; + char *tree_metadata_checksum; + GVariant *tree_metadata; +}; + +G_DEFINE_TYPE_WITH_CODE (OstreeRepoFile, ostree_repo_file, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_FILE, + ostree_repo_file_file_iface_init)) + +static void +ostree_repo_file_finalize (GObject *object) +{ + OstreeRepoFile *self; + + self = OSTREE_REPO_FILE (object); + + g_clear_pointer (&self->tree_contents, (GDestroyNotify) g_variant_unref); + g_clear_pointer (&self->tree_metadata, (GDestroyNotify) g_variant_unref); + g_free (self->cached_file_checksum); + g_free (self->tree_contents_checksum); + g_free (self->tree_metadata_checksum); + g_free (self->name); + + G_OBJECT_CLASS (ostree_repo_file_parent_class)->finalize (object); +} + +static void +ostree_repo_file_dispose (GObject *object) +{ + OstreeRepoFile *self; + + self = OSTREE_REPO_FILE (object); + + g_clear_object (&self->repo); + g_clear_object (&self->parent); + + if (G_OBJECT_CLASS (ostree_repo_file_parent_class)->dispose) + G_OBJECT_CLASS (ostree_repo_file_parent_class)->dispose (object); +} + +static void +ostree_repo_file_class_init (OstreeRepoFileClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = ostree_repo_file_finalize; + gobject_class->dispose = ostree_repo_file_dispose; +} + +static void +ostree_repo_file_init (OstreeRepoFile *self) +{ + self->index = -1; +} + +static gboolean +set_error_noent (GFile *self, GError **error) +{ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No such file or directory: %s", + gs_file_get_path_cached (self)); + return FALSE; +} + +OstreeRepoFile * +_ostree_repo_file_new_root (OstreeRepo *repo, + const char *contents_checksum, + const char *metadata_checksum) +{ + OstreeRepoFile *self; + + g_return_val_if_fail (repo != NULL, NULL); + g_return_val_if_fail (contents_checksum != NULL, NULL); + g_return_val_if_fail (strlen (contents_checksum) == OSTREE_SHA256_STRING_LEN, NULL); + g_return_val_if_fail (metadata_checksum != NULL, NULL); + g_return_val_if_fail (strlen (metadata_checksum) == OSTREE_SHA256_STRING_LEN, NULL); + + self = g_object_new (OSTREE_TYPE_REPO_FILE, NULL); + self->repo = g_object_ref (repo); + self->tree_contents_checksum = g_strdup (contents_checksum); + self->tree_metadata_checksum = g_strdup (metadata_checksum); + + return self; +} + +static OstreeRepoFile * +ostree_repo_file_new_child (OstreeRepoFile *parent, + const char *name) +{ + OstreeRepoFile *self; + size_t len; + + self = g_object_new (OSTREE_TYPE_REPO_FILE, NULL); + self->repo = g_object_ref (parent->repo); + self->parent = g_object_ref (parent); + self->name = g_strdup (name); + len = strlen(self->name); + if (self->name[len-1] == '/') + self->name[len-1] = '\0'; + + return self; +} + +OstreeRepoFile * +_ostree_repo_file_new_for_commit (OstreeRepo *repo, + const char *commit, + GError **error) +{ + g_autoptr(GVariant) commit_v = NULL; + g_autoptr(GVariant) tree_contents_csum_v = NULL; + g_autoptr(GVariant) tree_metadata_csum_v = NULL; + char tree_contents_csum[OSTREE_SHA256_STRING_LEN + 1]; + char tree_metadata_csum[OSTREE_SHA256_STRING_LEN + 1]; + + g_return_val_if_fail (repo != NULL, NULL); + g_return_val_if_fail (commit != NULL, NULL); + g_return_val_if_fail (strlen (commit) == OSTREE_SHA256_STRING_LEN, NULL); + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + commit, &commit_v, error)) + return NULL; + + /* PARSE OSTREE_OBJECT_TYPE_COMMIT */ + g_variant_get_child (commit_v, 6, "@ay", &tree_contents_csum_v); + ostree_checksum_inplace_from_bytes (g_variant_get_data (tree_contents_csum_v), + tree_contents_csum); + + g_variant_get_child (commit_v, 7, "@ay", &tree_metadata_csum_v); + ostree_checksum_inplace_from_bytes (g_variant_get_data (tree_metadata_csum_v), + tree_metadata_csum); + + return _ostree_repo_file_new_root (repo, tree_contents_csum, tree_metadata_csum); +} + +static gboolean +do_resolve (OstreeRepoFile *self, + GError **error) +{ + g_autoptr(GVariant) root_contents = NULL; + g_autoptr(GVariant) root_metadata = NULL; + + g_assert (self->parent == NULL); + + if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_DIR_TREE, + self->tree_contents_checksum, &root_contents, error)) + return FALSE; + + if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_DIR_META, + self->tree_metadata_checksum, &root_metadata, error)) + return FALSE; + + self->tree_metadata = root_metadata; + root_metadata = NULL; + self->tree_contents = root_contents; + root_contents = NULL; + + return TRUE; +} + +static gboolean +do_resolve_nonroot (OstreeRepoFile *self, + GError **error) +{ + gboolean is_dir; + int i; + g_autoptr(GVariant) container = NULL; + g_autoptr(GVariant) tree_contents = NULL; + g_autoptr(GVariant) tree_metadata = NULL; + g_autoptr(GVariant) contents_csum_v = NULL; + g_autoptr(GVariant) metadata_csum_v = NULL; + g_autofree char *tmp_checksum = NULL; + + if (!ostree_repo_file_ensure_resolved (self->parent, error)) + return FALSE; + + if (!self->parent->tree_contents) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, + "Not a directory"); + return FALSE; + } + + i = ostree_repo_file_tree_find_child (self->parent, self->name, &is_dir, &container); + + if (i < 0) + { + set_error_noent ((GFile*)self, error); + return FALSE; + } + + if (is_dir) + { + const char *name; + GVariant *files_variant; + + files_variant = g_variant_get_child_value (self->parent->tree_contents, 0); + self->index = g_variant_n_children (files_variant) + i; + g_clear_pointer (&files_variant, (GDestroyNotify) g_variant_unref); + + g_variant_get_child (container, i, "(&s@ay@ay)", + &name, &contents_csum_v, &metadata_csum_v); + + g_free (tmp_checksum); + tmp_checksum = ostree_checksum_from_bytes_v (contents_csum_v); + if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_DIR_TREE, + tmp_checksum, &tree_contents, + error)) + return FALSE; + + g_free (tmp_checksum); + tmp_checksum = ostree_checksum_from_bytes_v (metadata_csum_v); + if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_DIR_META, + tmp_checksum, &tree_metadata, + error)) + return FALSE; + + self->tree_contents = tree_contents; + tree_contents = NULL; + self->tree_metadata = tree_metadata; + tree_metadata = NULL; + self->tree_contents_checksum = ostree_checksum_from_bytes_v (contents_csum_v); + self->tree_metadata_checksum = ostree_checksum_from_bytes_v (metadata_csum_v); + } + else + self->index = i; + + return TRUE; +} + +gboolean +ostree_repo_file_ensure_resolved (OstreeRepoFile *self, + GError **error) +{ + if (self->parent == NULL) + { + if (self->tree_contents == NULL) + if (!do_resolve (self, error)) + return FALSE; + } + else + { + if (self->index == -1) + { + if (!do_resolve_nonroot (self, error)) + return FALSE; + } + } + + return TRUE; +} + +/** + * ostree_repo_file_get_xattrs: + * @self: #OstreeRepoFile + * @out_xattrs: (out) (optional): the extended attributes + * @cancellable: Cancellable + * @error: Error + */ +gboolean +ostree_repo_file_get_xattrs (OstreeRepoFile *self, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + if (!ostree_repo_file_ensure_resolved (self, error)) + return FALSE; + + g_autoptr(GVariant) ret_xattrs = NULL; + if (self->tree_metadata) + ret_xattrs = g_variant_get_child_value (self->tree_metadata, 3); + else + { + if (!ostree_repo_load_file (self->repo, ostree_repo_file_get_checksum (self), + NULL, NULL, &ret_xattrs, cancellable, error)) + return FALSE; + } + + ot_transfer_out_value(out_xattrs, &ret_xattrs); + return TRUE; +} + +GVariant * +ostree_repo_file_tree_get_contents (OstreeRepoFile *self) +{ + return self->tree_contents; +} + +GVariant * +ostree_repo_file_tree_get_metadata (OstreeRepoFile *self) +{ + return self->tree_metadata; +} + +void +ostree_repo_file_tree_set_metadata (OstreeRepoFile *self, + const char *checksum, + GVariant *metadata) +{ + g_clear_pointer (&self->tree_metadata, (GDestroyNotify) g_variant_unref); + self->tree_metadata = g_variant_ref (metadata); + g_free (self->tree_metadata_checksum); + self->tree_metadata_checksum = g_strdup (checksum); +} + +const char * +ostree_repo_file_tree_get_contents_checksum (OstreeRepoFile *self) +{ + return self->tree_contents_checksum; +} + +const char * +ostree_repo_file_tree_get_metadata_checksum (OstreeRepoFile *self) +{ + return self->tree_metadata_checksum; +} + +/** + * ostree_repo_file_get_repo: + * @self: + * + * Returns: (transfer none): Repository + */ +OstreeRepo * +ostree_repo_file_get_repo (OstreeRepoFile *self) +{ + return self->repo; +} + +/** + * ostree_repo_file_get_root: + * @self: + * + * Returns: (transfer none): The root directory for the commit referenced by this file + */ +OstreeRepoFile * +ostree_repo_file_get_root (OstreeRepoFile *self) +{ + OstreeRepoFile *parent = self; + + while (parent->parent) + parent = parent->parent; + return parent; +} + +const char * +ostree_repo_file_get_checksum (OstreeRepoFile *self) +{ + int n; + gboolean is_dir; + GVariant *files_variant; + GVariant *dirs_variant; + GVariant *csum_bytes; + + if (!self->parent) + return self->tree_metadata_checksum; + + if (self->cached_file_checksum) + return self->cached_file_checksum; + + n = ostree_repo_file_tree_find_child (self->parent, self->name, &is_dir, NULL); + g_assert (n >= 0); + + files_variant = g_variant_get_child_value (self->parent->tree_contents, 0); + dirs_variant = g_variant_get_child_value (self->parent->tree_contents, 1); + + if (is_dir) + { + g_variant_get_child (dirs_variant, n, + "(@s@ay@ay)", NULL, NULL, &csum_bytes); + } + else + { + g_variant_get_child (files_variant, n, + "(@s@ay)", NULL, &csum_bytes); + } + g_clear_pointer (&files_variant, (GDestroyNotify) g_variant_unref); + g_clear_pointer (&dirs_variant, (GDestroyNotify) g_variant_unref); + + self->cached_file_checksum = ostree_checksum_from_bytes_v (csum_bytes); + + g_variant_unref (csum_bytes); + + return self->cached_file_checksum; +} + +static gboolean +ostree_repo_file_is_native (GFile *file) +{ + return FALSE; +} + +static gboolean +ostree_repo_file_has_uri_scheme (GFile *file, + const char *uri_scheme) +{ + return g_ascii_strcasecmp (uri_scheme, "ostree") == 0; +} + +static char * +ostree_repo_file_get_uri_scheme (GFile *file) +{ + return g_strdup ("ostree"); +} + +static char * +ostree_repo_file_get_basename (GFile *file) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + return g_strdup (self->name); +} + +static char * +ostree_repo_file_get_path (GFile *file) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + OstreeRepoFile *parent; + GString *buf; + GSList *parents; + GSList *iter; + + buf = g_string_new (""); + parents = NULL; + + for (parent = self->parent; parent; parent = parent->parent) + parents = g_slist_prepend (parents, parent); + + if (parents && parents->next) + { + for (iter = parents->next; iter; iter = iter->next) + { + parent = iter->data; + g_string_append_c (buf, '/'); + g_string_append (buf, parent->name); + } + } + g_string_append_c (buf, '/'); + if (self->name) + g_string_append (buf, self->name); + + g_slist_free (parents); + + return g_string_free (buf, FALSE); +} + +static char * +ostree_repo_file_get_uri (GFile *file) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + const char *path; + char *uri_path; + char *ret; + OstreeRepoFile *root = ostree_repo_file_get_root (self); + + path = gs_file_get_path_cached (file); + uri_path = g_filename_to_uri (path, NULL, NULL); + g_assert (g_str_has_prefix (uri_path, "file://")); + ret = g_strconcat ("ostree://", + root->tree_contents_checksum, "/", root->tree_metadata_checksum, + uri_path+strlen("file://"), + NULL); + g_free (uri_path); + + return ret; +} + +static char * +ostree_repo_file_get_parse_name (GFile *file) +{ + return ostree_repo_file_get_uri (file); +} + +static GFile * +ostree_repo_file_get_parent (GFile *file) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + + return (GFile*)g_object_ref (self->parent); +} + +static GFile * +ostree_repo_file_dup (GFile *file) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + + if (self->parent) + return G_FILE (ostree_repo_file_new_child (self->parent, self->name)); + else + return G_FILE (_ostree_repo_file_new_root (self->repo, self->tree_contents_checksum, self->tree_metadata_checksum)); +} + +static guint +ostree_repo_file_hash (GFile *file) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + + if (self->parent) + return g_file_hash (self->parent) + g_str_hash (self->name); + else + return g_str_hash (self->tree_contents_checksum) + g_str_hash (self->tree_metadata_checksum); +} + +static gboolean +ostree_repo_file_equal (GFile *file1, + GFile *file2) +{ + OstreeRepoFile *self1 = OSTREE_REPO_FILE (file1); + OstreeRepoFile *self2 = OSTREE_REPO_FILE (file2); + + if (self1->parent && self2->parent) + { + return (g_str_equal (self1->name, self2->name) && + g_file_equal ((GFile*)self1->parent, (GFile*)self2->parent)); + } + else if (!self1->parent && !self2->parent) + { + return (g_str_equal (self1->tree_contents_checksum, self2->tree_contents_checksum) && + g_str_equal (self1->tree_metadata_checksum, self2->tree_metadata_checksum)); + } + else + return FALSE; +} + +static const char * +match_prefix (const char *path, + const char *prefix) +{ + int prefix_len; + + prefix_len = strlen (prefix); + if (strncmp (path, prefix, prefix_len) != 0) + return NULL; + + /* Handle the case where prefix is the root, so that + * the IS_DIR_SEPRARATOR check below works */ + if (prefix_len > 0 && + G_IS_DIR_SEPARATOR (prefix[prefix_len-1])) + prefix_len--; + + return path + prefix_len; +} + +static gboolean +ostree_repo_file_prefix_matches (GFile *parent, + GFile *descendant) +{ + const char *remainder; + const char *parent_path; + const char *descendant_path; + + parent_path = gs_file_get_path_cached (parent); + descendant_path = gs_file_get_path_cached (descendant); + remainder = match_prefix (descendant_path, parent_path); + if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder)) + return TRUE; + return FALSE; +} + +static char * +ostree_repo_file_get_relative_path (GFile *parent, + GFile *descendant) +{ + const char *remainder; + const char *parent_path; + const char *descendant_path; + + parent_path = gs_file_get_path_cached (parent); + descendant_path = gs_file_get_path_cached (descendant); + remainder = match_prefix (descendant_path, parent_path); + + if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder)) + return g_strdup (remainder + 1); + return NULL; +} + +static GFile * +ostree_repo_file_resolve_relative_path (GFile *file, + const char *relative_path) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + OstreeRepoFile *parent; + char *filename; + const char *rest; + GFile *ret; + + if (g_path_is_absolute (relative_path)) + { + g_assert (*relative_path == '/'); + + if (strcmp (relative_path, "/") == 0) + return (GFile*)g_object_ref (ostree_repo_file_get_root (self)); + + if (self->parent) + return ostree_repo_file_resolve_relative_path ((GFile*)ostree_repo_file_get_root (self), + relative_path+1); + else + relative_path = relative_path+1; + } + + rest = strchr (relative_path, '/'); + if (rest) + { + rest += 1; + filename = g_strndup (relative_path, rest - relative_path); + } + else + filename = g_strdup (relative_path); + + parent = ostree_repo_file_new_child (self, filename); + g_free (filename); + + if (!rest) + ret = (GFile*)parent; + else + { + ret = ostree_repo_file_resolve_relative_path ((GFile*)parent, rest); + g_clear_object (&parent); + } + return ret; +} + +static GFileEnumerator * +ostree_repo_file_enumerate_children (GFile *file, + const char *attributes, + GFileQueryInfoFlags flags, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + return _ostree_repo_file_enumerator_new (self, + attributes, flags, + cancellable, error); +} + +static GFile * +ostree_repo_file_get_child_for_display_name (GFile *file, + const char *display_name, + GError **error) +{ + return g_file_get_child (file, display_name); +} + +static void +set_info_from_dirmeta (GFileInfo *info, + GVariant *metadata) +{ + guint32 uid, gid, mode; + + g_file_info_set_attribute_uint32 (info, "standard::type", G_FILE_TYPE_DIRECTORY); + + /* PARSE OSTREE_OBJECT_TYPE_DIR_META */ + g_variant_get (metadata, "(uuu@a(ayay))", + &uid, &gid, &mode, NULL); + uid = GUINT32_FROM_BE (uid); + gid = GUINT32_FROM_BE (gid); + mode = GUINT32_FROM_BE (mode); + + g_file_info_set_attribute_uint32 (info, "unix::uid", uid); + g_file_info_set_attribute_uint32 (info, "unix::gid", gid); + g_file_info_set_attribute_uint32 (info, "unix::mode", mode); +} + +static gboolean +query_child_info_dir (OstreeRepo *repo, + const char *metadata_checksum, + GFileAttributeMatcher *matcher, + GFileQueryInfoFlags flags, + GFileInfo **out_info, + GCancellable *cancellable, + GError **error) +{ + + g_autoptr(GFileInfo) ret_info = g_file_info_new (); + + g_file_info_set_attribute_uint32 (ret_info, "standard::type", + G_FILE_TYPE_DIRECTORY); + + if (g_file_attribute_matcher_matches (matcher, "unix::mode")) + { + g_autoptr(GVariant) metadata = NULL; + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_DIR_META, + metadata_checksum, &metadata, error)) + return FALSE; + + set_info_from_dirmeta (ret_info, metadata); + } + + ot_transfer_out_value(out_info, &ret_info); + return TRUE; +} + +/** + * ostree_repo_file_tree_find_child: + * @self: #OstreeRepoFile + * @name: name of the child + * @is_dir: (out caller-allocates): + * @out_container: (out): + */ +int +ostree_repo_file_tree_find_child (OstreeRepoFile *self, + const char *name, + gboolean *is_dir, + GVariant **out_container) +{ + int i; + GVariant *files_variant = NULL; + GVariant *dirs_variant = NULL; + GVariant *ret_container = NULL; + + files_variant = g_variant_get_child_value (self->tree_contents, 0); + dirs_variant = g_variant_get_child_value (self->tree_contents, 1); + + i = -1; + if (ot_variant_bsearch_str (files_variant, name, &i)) + { + *is_dir = FALSE; + ret_container = files_variant; + files_variant = NULL; + } + else + { + if (ot_variant_bsearch_str (dirs_variant, name, &i)) + { + *is_dir = TRUE; + ret_container = dirs_variant; + dirs_variant = NULL; + } + else + { + i = -1; + } + } + if (ret_container && out_container) + { + *out_container = ret_container; + ret_container = NULL; + } + g_clear_pointer (&ret_container, (GDestroyNotify) g_variant_unref); + g_clear_pointer (&files_variant, (GDestroyNotify) g_variant_unref); + g_clear_pointer (&dirs_variant, (GDestroyNotify) g_variant_unref); + return i; +} + +/** + * ostree_repo_file_tree_query_child: + * @self: #OstreeRepoFile + * @n: + * @attributes: + * @flags: + * @out_info: (out): + * @cancellable: Cancellable + * @error: Error + */ +gboolean +ostree_repo_file_tree_query_child (OstreeRepoFile *self, + int n, + const char *attributes, + GFileQueryInfoFlags flags, + GFileInfo **out_info, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + const char *name = NULL; + int c; + g_autoptr(GFileInfo) ret_info = NULL; + g_autoptr(GVariant) files_variant = NULL; + g_autoptr(GVariant) dirs_variant = NULL; + g_autoptr(GVariant) content_csum_v = NULL; + g_autoptr(GVariant) meta_csum_v = NULL; + char tmp_checksum[OSTREE_SHA256_STRING_LEN+1]; + GFileAttributeMatcher *matcher = NULL; + + if (!ostree_repo_file_ensure_resolved (self, error)) + goto out; + + matcher = g_file_attribute_matcher_new (attributes); + + g_assert (self->tree_contents); + + files_variant = g_variant_get_child_value (self->tree_contents, 0); + dirs_variant = g_variant_get_child_value (self->tree_contents, 1); + + c = g_variant_n_children (files_variant); + if (n < c) + { + const guchar *csum_bytes; + + g_variant_get_child (files_variant, n, "(&s@ay)", &name, &content_csum_v); + csum_bytes = ostree_checksum_bytes_peek_validate (content_csum_v, error); + if (csum_bytes == NULL) + goto out; + + ostree_checksum_inplace_from_bytes (csum_bytes, tmp_checksum); + + if (!ostree_repo_load_file (self->repo, tmp_checksum, NULL, &ret_info, NULL, + cancellable, error)) + goto out; + } + else + { + n -= c; + + c = g_variant_n_children (dirs_variant); + + if (n < c) + { + const guchar *csum_bytes; + + g_variant_get_child (dirs_variant, n, "(&s@ay@ay)", + &name, NULL, &meta_csum_v); + csum_bytes = ostree_checksum_bytes_peek_validate (meta_csum_v, error); + if (csum_bytes == NULL) + goto out; + + ostree_checksum_inplace_from_bytes (csum_bytes, tmp_checksum); + + if (!query_child_info_dir (self->repo, tmp_checksum, + matcher, flags, &ret_info, + cancellable, error)) + goto out; + } + } + + if (name) + { + g_file_info_set_attribute_byte_string (ret_info, "standard::name", + name); + g_file_info_set_attribute_string (ret_info, "standard::display-name", + name); + if (*name == '.') + g_file_info_set_is_hidden (ret_info, TRUE); + } + else + { + g_clear_object (&ret_info); + } + + ret = TRUE; + ot_transfer_out_value(out_info, &ret_info); + out: + if (matcher) + g_file_attribute_matcher_unref (matcher); + return ret; +} + +static GFileInfo * +ostree_repo_file_query_info (GFile *file, + const char *attributes, + GFileQueryInfoFlags flags, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + g_autoptr(GFileInfo) info = NULL; + + if (!ostree_repo_file_ensure_resolved (self, error)) + return NULL; + + if (!self->parent) + { + info = g_file_info_new (); + set_info_from_dirmeta (info, self->tree_metadata); + } + else + { + if (!ostree_repo_file_tree_query_child (self->parent, self->index, + attributes, flags, + &info, cancellable, error)) + return NULL; + g_assert (info != NULL); + } + + return g_steal_pointer (&info); +} + +static GFileAttributeInfoList * +ostree_repo_file_query_settable_attributes (GFile *file, + GCancellable *cancellable, + GError **error) +{ + return g_file_attribute_info_list_new (); +} + +static GFileAttributeInfoList * +ostree_repo_file_query_writable_namespaces (GFile *file, + GCancellable *cancellable, + GError **error) +{ + return g_file_attribute_info_list_new (); +} + +static GFileInputStream * +ostree_repo_file_read (GFile *file, + GCancellable *cancellable, + GError **error) +{ + OstreeRepoFile *self = OSTREE_REPO_FILE (file); + const char *checksum; + g_autoptr(GInputStream) ret_stream = NULL; + + if (!ostree_repo_file_ensure_resolved (self, error)) + return FALSE; + + if (self->tree_contents) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY, + "Can't open directory"); + return NULL; + } + + checksum = ostree_repo_file_get_checksum (self); + + g_autoptr(GFileInfo) finfo = NULL; + if (!ostree_repo_load_file (self->repo, checksum, NULL, + &finfo, NULL, cancellable, error)) + return NULL; + if (g_file_info_get_file_type (finfo) == G_FILE_TYPE_REGULAR) + { + if (!ostree_repo_load_file (self->repo, checksum, &ret_stream, + NULL, NULL, cancellable, error)) + return NULL; + } + else + { + g_autoptr(GFile) parent = g_file_get_parent (file); + const char *target = g_file_info_get_symlink_target (finfo); + g_autoptr(GFile) dest = g_file_resolve_relative_path (parent, target); + return g_file_read (dest, cancellable, error); + } + + return g_steal_pointer (&ret_stream); +} + +static void +ostree_repo_file_file_iface_init (GFileIface *iface) +{ + iface->dup = ostree_repo_file_dup; + iface->hash = ostree_repo_file_hash; + iface->equal = ostree_repo_file_equal; + iface->is_native = ostree_repo_file_is_native; + iface->has_uri_scheme = ostree_repo_file_has_uri_scheme; + iface->get_uri_scheme = ostree_repo_file_get_uri_scheme; + iface->get_basename = ostree_repo_file_get_basename; + iface->get_path = ostree_repo_file_get_path; + iface->get_uri = ostree_repo_file_get_uri; + iface->get_parse_name = ostree_repo_file_get_parse_name; + iface->get_parent = ostree_repo_file_get_parent; + iface->prefix_matches = ostree_repo_file_prefix_matches; + iface->get_relative_path = ostree_repo_file_get_relative_path; + iface->resolve_relative_path = ostree_repo_file_resolve_relative_path; + iface->get_child_for_display_name = ostree_repo_file_get_child_for_display_name; + iface->set_display_name = NULL; + iface->enumerate_children = ostree_repo_file_enumerate_children; + iface->query_info = ostree_repo_file_query_info; + iface->query_filesystem_info = NULL; + iface->find_enclosing_mount = NULL; + iface->query_settable_attributes = ostree_repo_file_query_settable_attributes; + iface->query_writable_namespaces = ostree_repo_file_query_writable_namespaces; + iface->set_attribute = NULL; + iface->set_attributes_from_info = NULL; + iface->read_fn = ostree_repo_file_read; + iface->append_to = NULL; + iface->create = NULL; + iface->replace = NULL; + iface->open_readwrite = NULL; + iface->create_readwrite = NULL; + iface->replace_readwrite = NULL; + iface->delete_file = NULL; + iface->trash = NULL; + iface->make_directory = NULL; + iface->make_symbolic_link = NULL; + iface->copy = NULL; + iface->move = NULL; + iface->monitor_dir = NULL; + iface->monitor_file = NULL; + + iface->supports_thread_contexts = TRUE; +} diff --git a/src/libostree/ostree-repo-file.h b/src/libostree/ostree-repo-file.h new file mode 100644 index 0000000..fd65890 --- /dev/null +++ b/src/libostree/ostree-repo-file.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_REPO_FILE (ostree_repo_file_get_type ()) +#define OSTREE_REPO_FILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_REPO_FILE, OstreeRepoFile)) +#define OSTREE_REPO_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_REPO_FILE, OstreeRepoFileClass)) +#define OSTREE_IS_REPO_FILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_REPO_FILE)) +#define OSTREE_IS_REPO_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_REPO_FILE)) +#define OSTREE_REPO_FILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_REPO_FILE, OstreeRepoFileClass)) + +typedef struct _OstreeRepoFileClass OstreeRepoFileClass; + +struct _OstreeRepoFileClass +{ + GObjectClass parent_class; +}; + +_OSTREE_PUBLIC +GType ostree_repo_file_get_type (void) G_GNUC_CONST; + +_OSTREE_PUBLIC +gboolean ostree_repo_file_ensure_resolved (OstreeRepoFile *self, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_file_get_xattrs (OstreeRepoFile *self, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeRepo * ostree_repo_file_get_repo (OstreeRepoFile *self); +_OSTREE_PUBLIC +OstreeRepoFile * ostree_repo_file_get_root (OstreeRepoFile *self); + +_OSTREE_PUBLIC +void ostree_repo_file_tree_set_metadata (OstreeRepoFile *self, + const char *checksum, + GVariant *metadata); + +_OSTREE_PUBLIC +const char *ostree_repo_file_tree_get_contents_checksum (OstreeRepoFile *self); +_OSTREE_PUBLIC +const char *ostree_repo_file_tree_get_metadata_checksum (OstreeRepoFile *self); + +_OSTREE_PUBLIC +GVariant *ostree_repo_file_tree_get_contents (OstreeRepoFile *self); +_OSTREE_PUBLIC +GVariant *ostree_repo_file_tree_get_metadata (OstreeRepoFile *self); + +_OSTREE_PUBLIC +const char * ostree_repo_file_get_checksum (OstreeRepoFile *self); + +_OSTREE_PUBLIC +int ostree_repo_file_tree_find_child (OstreeRepoFile *self, + const char *name, + gboolean *is_dir, + GVariant **out_container); + +_OSTREE_PUBLIC +gboolean ostree_repo_file_tree_query_child (OstreeRepoFile *self, + int n, + const char *attributes, + GFileQueryInfoFlags flags, + GFileInfo **out_info, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-finder-avahi-parser.c b/src/libostree/ostree-repo-finder-avahi-parser.c new file mode 100644 index 0000000..afc9790 --- /dev/null +++ b/src/libostree/ostree-repo-finder-avahi-parser.c @@ -0,0 +1,139 @@ +/* + * Copyright © 2016 Kinvolk GmbH + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Krzesimir Nowak + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-repo-finder-avahi.h" +#include "ostree-repo-finder-avahi-private.h" + +/* Reference: RFC 6763, §6. */ +static gboolean +parse_txt_record (const guint8 *txt, + gsize txt_len, + const gchar **key, + gsize *key_len, + const guint8 **value, + gsize *value_len) +{ + gsize i; + + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (key_len != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (value_len != NULL, FALSE); + + /* RFC 6763, §6.1. */ + if (txt_len > 8900) + return FALSE; + + *key = (const gchar *) txt; + *key_len = 0; + *value = NULL; + *value_len = 0; + + for (i = 0; i < txt_len; i++) + { + if (txt[i] >= 0x20 && txt[i] <= 0x7e && txt[i] != '=') + { + /* Key character. */ + *key_len = *key_len + 1; + continue; + } + else if (*key_len > 0 && txt[i] == '=') + { + /* Separator. */ + *value = txt + (i + 1); + *value_len = txt_len - (i + 1); + return TRUE; + } + else + { + return FALSE; + } + } + + /* The entire TXT record is the key; there is no ‘=’ or value. */ + *value = NULL; + *value_len = 0; + + return (*key_len > 0); +} + +/* TODO: Docs. Return value is only valid as long as @txt is. Reference: RFC 6763, §6. */ +GHashTable * +_ostree_txt_records_parse (AvahiStringList *txt) +{ + AvahiStringList *l; + g_autoptr(GHashTable) out = NULL; + + out = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_bytes_unref); + + for (l = txt; l != NULL; l = avahi_string_list_get_next (l)) + { + const guint8 *txt; + gsize txt_len; + const gchar *key; + const guint8 *value; + gsize key_len, value_len; + g_autofree gchar *key_allocated = NULL; + g_autoptr(GBytes) value_allocated = NULL; + + txt = avahi_string_list_get_text (l); + txt_len = avahi_string_list_get_size (l); + + if (!parse_txt_record (txt, txt_len, &key, &key_len, &value, &value_len)) + { + g_debug ("Ignoring invalid TXT record of length %" G_GSIZE_FORMAT, + txt_len); + continue; + } + + key_allocated = g_ascii_strdown (key, key_len); + + if (g_hash_table_lookup_extended (out, key_allocated, NULL, NULL)) + { + g_debug ("Ignoring duplicate TXT record ‘%s’", key_allocated); + continue; + } + + /* Distinguish between the case where the entire record is the key + * (value == NULL) and the case where the record is the key + ‘=’ and the + * value is empty (value != NULL && value_len == 0). */ + if (value != NULL) + value_allocated = g_bytes_new_static (value, value_len); + + g_hash_table_insert (out, g_steal_pointer (&key_allocated), g_steal_pointer (&value_allocated)); + } + + return g_steal_pointer (&out); +} diff --git a/src/libostree/ostree-repo-finder-avahi-private.h b/src/libostree/ostree-repo-finder-avahi-private.h new file mode 100644 index 0000000..5a96038 --- /dev/null +++ b/src/libostree/ostree-repo-finder-avahi-private.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include +#include + +G_BEGIN_DECLS + +GHashTable *_ostree_txt_records_parse (AvahiStringList *txt); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-finder-avahi.c b/src/libostree/ostree-repo-finder-avahi.c new file mode 100644 index 0000000..1b085ea --- /dev/null +++ b/src/libostree/ostree-repo-finder-avahi.c @@ -0,0 +1,1536 @@ +/* + * Copyright © 2016 Kinvolk GmbH + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Krzesimir Nowak + * - Philip Withnall + */ + +#include "config.h" + +#ifdef HAVE_AVAHI +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* HAVE_AVAHI */ + +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-repo-finder.h" +#include "ostree-repo-finder-avahi.h" + +#ifdef HAVE_AVAHI +#include "ostree-bloom-private.h" +#include "ostree-remote-private.h" +#include "ostree-repo-private.h" +#include "ostree-repo.h" +#include "ostree-repo-finder-avahi-private.h" +#include "ostree-soup-uri.h" +#include "otutil.h" +#endif /* HAVE_AVAHI */ + +/** + * SECTION:ostree-repo-finder-avahi + * @title: OstreeRepoFinderAvahi + * @short_description: Finds remote repositories from ref names by looking at + * adverts of refs from peers on the local network + * @stability: Unstable + * @include: libostree/ostree-repo-finder-avahi.h + * + * #OstreeRepoFinderAvahi is an implementation of #OstreeRepoFinder which looks + * for refs being hosted by peers on the local network. + * + * Any ref which matches by collection ID and ref name is returned as a result, + * with no limitations on the peers which host them, as long as they are + * accessible over the local network, and their adverts reach this machine via + * DNS-SD/mDNS. + * + * For each repository which is found, a result will be returned for the + * intersection of the refs being searched for, and the refs in `refs/mirrors` + * in the remote repository. + * + * DNS-SD resolution is performed using Avahi, which will continue to scan for + * matching peers throughout the lifetime of the process. It’s recommended that + * ostree_repo_finder_avahi_start() be called early on in the process’ lifetime, + * and the #GMainContext which is passed to ostree_repo_finder_avahi_new() + * continues to be iterated until ostree_repo_finder_avahi_stop() is called. + * + * The values stored in DNS-SD TXT records are stored as big-endian whenever + * endianness is relevant. + * + * Internally, #OstreeRepoFinderAvahi has an Avahi client, browser and resolver + * which work in the background to track all available peers on the local + * network. Whenever a resolve request is made using + * ostree_repo_finder_resolve_async(), the request is blocked until the + * background tracking is in a consistent state (typically this only happens at + * startup), and is then answered using the current cache of background data. + * The Avahi client tracks the #OstreeRepoFinderAvahi’s connection with the + * Avahi D-Bus service. The browser looks for DNS-SD peers on the local network; + * and the resolver is used to retrieve information about services advertised by + * each peer, including the services’ TXT records. + * + * Since: 2018.6 + */ + +#ifdef HAVE_AVAHI +/* FIXME: Submit these upstream */ +G_DEFINE_AUTOPTR_CLEANUP_FUNC (AvahiClient, avahi_client_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (AvahiServiceBrowser, avahi_service_browser_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (AvahiServiceResolver, avahi_service_resolver_free) + +/* FIXME: Register this with IANA? https://tools.ietf.org/html/rfc6335#section-5.2 */ +const gchar * const OSTREE_AVAHI_SERVICE_TYPE = "_ostree_repo._tcp"; + +static const gchar * +ostree_avahi_client_state_to_string (AvahiClientState state) +{ + switch (state) + { + case AVAHI_CLIENT_S_REGISTERING: + return "registering"; + case AVAHI_CLIENT_S_RUNNING: + return "running"; + case AVAHI_CLIENT_S_COLLISION: + return "collision"; + case AVAHI_CLIENT_CONNECTING: + return "connecting"; + case AVAHI_CLIENT_FAILURE: + return "failure"; + default: + return "unknown"; + } +} + +static const gchar * +ostree_avahi_resolver_event_to_string (AvahiResolverEvent event) +{ + switch (event) + { + case AVAHI_RESOLVER_FOUND: + return "found"; + case AVAHI_RESOLVER_FAILURE: + return "failure"; + default: + return "unknown"; + } +} + +static const gchar * +ostree_avahi_browser_event_to_string (AvahiBrowserEvent event) +{ + switch (event) + { + case AVAHI_BROWSER_NEW: + return "new"; + case AVAHI_BROWSER_REMOVE: + return "remove"; + case AVAHI_BROWSER_CACHE_EXHAUSTED: + return "cache-exhausted"; + case AVAHI_BROWSER_ALL_FOR_NOW: + return "all-for-now"; + case AVAHI_BROWSER_FAILURE: + return "failure"; + default: + return "unknown"; + } +} + +typedef struct +{ + gchar *uri; + OstreeRemote *keyring_remote; /* (owned) */ +} UriAndKeyring; + +static void +uri_and_keyring_free (UriAndKeyring *data) +{ + g_free (data->uri); + ostree_remote_unref (data->keyring_remote); + g_free (data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (UriAndKeyring, uri_and_keyring_free) + +static UriAndKeyring * +uri_and_keyring_new (const gchar *uri, + OstreeRemote *keyring_remote) +{ + g_autoptr(UriAndKeyring) data = NULL; + + data = g_new0 (UriAndKeyring, 1); + data->uri = g_strdup (uri); + data->keyring_remote = ostree_remote_ref (keyring_remote); + + return g_steal_pointer (&data); +} + +static guint +uri_and_keyring_hash (gconstpointer key) +{ + const UriAndKeyring *_key = key; + + return g_str_hash (_key->uri) ^ g_str_hash (_key->keyring_remote->keyring); +} + +static gboolean +uri_and_keyring_equal (gconstpointer a, + gconstpointer b) +{ + const UriAndKeyring *_a = a, *_b = b; + + return (g_str_equal (_a->uri, _b->uri) && + g_str_equal (_a->keyring_remote->keyring, _b->keyring_remote->keyring)); +} + +/* This must return a valid remote name (suitable for use in a refspec). */ +static gchar * +uri_and_keyring_to_name (UriAndKeyring *data) +{ + g_autofree gchar *escaped_uri = g_uri_escape_string (data->uri, NULL, FALSE); + g_autofree gchar *escaped_keyring = g_uri_escape_string (data->keyring_remote->keyring, NULL, FALSE); + + /* FIXME: Need a better separator than `_`, since it’s not escaped in the input. */ + g_autofree gchar *out = g_strdup_printf ("%s_%s", escaped_uri, escaped_keyring); + + for (gsize i = 0; out[i] != '\0'; i++) + { + if (out[i] == '%') + out[i] = '_'; + } + + g_return_val_if_fail (ostree_validate_remote_name (out, NULL), NULL); + + return g_steal_pointer (&out); +} + +/* Internal structure representing a service found advertised by a peer on the + * local network. This includes details for connecting to the service, and the + * metadata associated with the advert (@txt). */ +typedef struct +{ + gchar *name; + gchar *domain; + gchar *address; + guint16 port; + AvahiStringList *txt; +} OstreeAvahiService; + +static void +ostree_avahi_service_free (OstreeAvahiService *service) +{ + g_free (service->name); + g_free (service->domain); + g_free (service->address); + avahi_string_list_free (service->txt); + g_free (service); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeAvahiService, ostree_avahi_service_free) + +/* Convert an AvahiAddress to a string which is suitable for use in URIs (for + * example). Take into account the scope ID, if the address is IPv6 and a + * link-local address. + * (See https://en.wikipedia.org/wiki/IPv6_address#Link-local_addresses_and_zone_indices and + * https://github.com/lathiat/avahi/issues/110.) */ +static gchar * +address_to_string (const AvahiAddress *address, + AvahiIfIndex interface) +{ + char address_string[AVAHI_ADDRESS_STR_MAX]; + + avahi_address_snprint (address_string, sizeof (address_string), address); + + switch (address->proto) + { + case AVAHI_PROTO_INET6: + if (IN6_IS_ADDR_LINKLOCAL (address->data.data) || + IN6_IS_ADDR_LOOPBACK (address->data.data)) + return g_strdup_printf ("%s%%%d", address_string, interface); + /* else fall through */ + case AVAHI_PROTO_INET: + case AVAHI_PROTO_UNSPEC: + default: + return g_strdup (address_string); + } +} + +static OstreeAvahiService * +ostree_avahi_service_new (const gchar *name, + const gchar *domain, + const AvahiAddress *address, + AvahiIfIndex interface, + guint16 port, + AvahiStringList *txt) +{ + g_autoptr(OstreeAvahiService) service = NULL; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (domain != NULL, NULL); + g_return_val_if_fail (address != NULL, NULL); + g_return_val_if_fail (port > 0, NULL); + + service = g_new0 (OstreeAvahiService, 1); + + service->name = g_strdup (name); + service->domain = g_strdup (domain); + service->address = address_to_string (address, interface); + service->port = port; + service->txt = avahi_string_list_copy (txt); + + return g_steal_pointer (&service); +} + +/* Check whether @str is entirely lower case. */ +static gboolean +str_is_lowercase (const gchar *str) +{ + gsize i; + + for (i = 0; str[i] != '\0'; i++) + { + if (!g_ascii_islower (str[i])) + return FALSE; + } + + return TRUE; +} + +/* Look up @key in the @attributes table derived from a TXT record, and validate + * that its value is of type @value_type. If the key is not found, or its value + * is of the wrong type or is not in normal form, %NULL is returned. @key must + * be lowercase in order to match reliably. */ +static GVariant * +_ostree_txt_records_lookup_variant (GHashTable *attributes, + const gchar *key, + const GVariantType *value_type) +{ + GBytes *value; + g_autoptr(GVariant) variant = NULL; + + g_return_val_if_fail (attributes != NULL, NULL); + g_return_val_if_fail (str_is_lowercase (key), NULL); + g_return_val_if_fail (value_type != NULL, NULL); + + value = g_hash_table_lookup (attributes, key); + + if (value == NULL) + { + g_debug ("TXT attribute ‘%s’ not found.", key); + return NULL; + } + + variant = g_variant_new_from_bytes (value_type, value, FALSE); + + if (!g_variant_is_normal_form (variant)) + { + g_debug ("TXT attribute ‘%s’ value is not in normal form. Ignoring.", key); + return NULL; + } + + return g_steal_pointer (&variant); +} + +/* Bloom hash function family for #OstreeCollectionRef, parameterised by @k. */ +static guint64 +ostree_collection_ref_bloom_hash (gconstpointer element, + guint8 k) +{ + const OstreeCollectionRef *ref = element; + + return ostree_str_bloom_hash (ref->collection_id, k) ^ ostree_str_bloom_hash (ref->ref_name, k); +} + +/* Return the (possibly empty) subset of @refs which are possibly in the given + * encoded bloom filter, @bloom_encoded. The returned array is not + * %NULL-terminated. If there is an error decoding the bloom filter (invalid + * type, zero length, unknown hash function), %NULL will be returned. */ +static GPtrArray * +bloom_refs_intersection (GVariant *bloom_encoded, + const OstreeCollectionRef * const *refs) +{ + g_autoptr(OstreeBloom) bloom = NULL; + g_autoptr(GVariant) bloom_variant = NULL; + guint8 k, hash_id; + OstreeBloomHashFunc hash_func; + const guint8 *bloom_bytes; + gsize n_bloom_bytes; + g_autoptr(GBytes) bytes = NULL; + gsize i; + g_autoptr(GPtrArray) possible_refs = NULL; /* (element-type OstreeCollectionRef) */ + + g_variant_get (bloom_encoded, "(yy@ay)", &k, &hash_id, &bloom_variant); + + if (k == 0) + return NULL; + + switch (hash_id) + { + case 1: + hash_func = ostree_collection_ref_bloom_hash; + break; + default: + return NULL; + } + + bloom_bytes = g_variant_get_fixed_array (bloom_variant, &n_bloom_bytes, sizeof (guint8)); + bytes = g_bytes_new_static (bloom_bytes, n_bloom_bytes); + bloom = ostree_bloom_new_from_bytes (bytes, k, hash_func); + + possible_refs = g_ptr_array_new_with_free_func (NULL); + + for (i = 0; refs[i] != NULL; i++) + { + if (ostree_bloom_maybe_contains (bloom, refs[i])) + g_ptr_array_add (possible_refs, (gpointer) refs[i]); + } + + return g_steal_pointer (&possible_refs); +} + +/* Given a @summary_map of ref name to commit details, and the @collection_id + * for all the refs in the @summary_map (which may be %NULL if the summary does + * not specify one), add the refs to @refs_and_checksums. + * + * The @summary_map is validated as it’s iterated over; on error, @error will be + * set and @refs_and_checksums will be left in an undefined state. */ +static gboolean +fill_refs_and_checksums_from_summary_map (GVariantIter *summary_map, + const gchar *collection_id, + GHashTable *refs_and_checksums /* (element-type OstreeCollectionRef utf8) */, + GError **error) +{ + g_autofree gchar *ref_name = NULL; + g_autoptr(GVariant) checksum_variant = NULL; + + while (g_variant_iter_loop (summary_map, "(s(t@aya{sv}))", + (gpointer *) &ref_name, NULL, + (gpointer *) &checksum_variant, NULL)) + { + const OstreeCollectionRef ref = { (gchar *) collection_id, ref_name }; + + if (!ostree_validate_rev (ref_name, error)) + return FALSE; + if (!ostree_validate_structureof_csum_v (checksum_variant, error)) + return FALSE; + + if (g_hash_table_contains (refs_and_checksums, &ref)) + { + g_autofree gchar *checksum_string = ostree_checksum_from_bytes_v (checksum_variant); + + g_hash_table_replace (refs_and_checksums, + ostree_collection_ref_dup (&ref), + g_steal_pointer (&checksum_string)); + } + } + + return TRUE; +} + +/* Given a @summary file, add the refs it lists to @refs_and_checksums. This + * includes the main refs list in the summary, and the map of collection IDs + * to further refs lists. + * + * The @summary is validated as it’s explored; on error, @error will be + * set and @refs_and_checksums will be left in an undefined state. */ +static gboolean +fill_refs_and_checksums_from_summary (GVariant *summary, + GHashTable *refs_and_checksums /* (element-type OstreeCollectionRef utf8) */, + GError **error) +{ + g_autoptr(GVariant) ref_map_v = NULL; + g_autoptr(GVariant) additional_metadata_v = NULL; + g_autoptr(GVariantIter) ref_map = NULL; + g_auto(GVariantDict) additional_metadata = OT_VARIANT_BUILDER_INITIALIZER; + const gchar *collection_id; + g_autoptr(GVariantIter) collection_map = NULL; + + ref_map_v = g_variant_get_child_value (summary, 0); + additional_metadata_v = g_variant_get_child_value (summary, 1); + + ref_map = g_variant_iter_new (ref_map_v); + g_variant_dict_init (&additional_metadata, additional_metadata_v); + + /* If the summary file specifies a collection ID (to apply to all the refs in its + * ref map), use that to start matching against the queried refs. Otherwise, + * it might specify all its refs in a collection-map; or the summary format is + * old and unsuitable for P2P redistribution and we should bail. */ + if (g_variant_dict_lookup (&additional_metadata, OSTREE_SUMMARY_COLLECTION_ID, "&s", &collection_id)) + { + if (!ostree_validate_collection_id (collection_id, error)) + return FALSE; + if (!fill_refs_and_checksums_from_summary_map (ref_map, collection_id, refs_and_checksums, error)) + return FALSE; + } + + g_clear_pointer (&ref_map, (GDestroyNotify) g_variant_iter_free); + + /* Repeat for the other collections listed in the summary. */ + if (g_variant_dict_lookup (&additional_metadata, OSTREE_SUMMARY_COLLECTION_MAP, "a{sa(s(taya{sv}))}", &collection_map)) + { + while (g_variant_iter_loop (collection_map, "{sa(s(taya{sv}))}", &collection_id, &ref_map)) + { + if (!ostree_validate_collection_id (collection_id, error)) + return FALSE; + if (!fill_refs_and_checksums_from_summary_map (ref_map, collection_id, refs_and_checksums, error)) + return FALSE; + } + } + + return TRUE; +} + +static gboolean +remove_null_checksum_refs_cb (gpointer key, + gpointer value, + gpointer user_data) +{ + const char *checksum = value; + + return (checksum == NULL); +} + +/* Given a summary file (@summary_bytes), extract the refs it lists, and use that + * to fill in the checksums in the @supported_ref_to_checksum map. This includes + * the main refs list in the summary, and the map of collection IDs to further + * refs lists. + * + * The @summary is validated as it’s explored; on error, @error will be + * set and %FALSE will be returned. If the intersection of the summary file refs + * and the keys in @supported_ref_to_checksum is empty, an error is set. */ +static gboolean +get_refs_and_checksums_from_summary (GBytes *summary_bytes, + GHashTable *supported_ref_to_checksum /* (element-type OstreeCollectionRef utf8) */, + OstreeRemote *remote, + GError **error) +{ + g_autoptr(GVariant) summary = g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, summary_bytes, FALSE)); + guint removed_refs; + + if (!g_variant_is_normal_form (summary)) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Not normal form"); + return FALSE; + } + if (!g_variant_is_of_type (summary, OSTREE_SUMMARY_GVARIANT_FORMAT)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Doesn't match variant type '%s'", + (char *)OSTREE_SUMMARY_GVARIANT_FORMAT); + return FALSE; + } + + if (!fill_refs_and_checksums_from_summary (summary, supported_ref_to_checksum, error)) + return FALSE; + + removed_refs = g_hash_table_foreach_remove (supported_ref_to_checksum, remove_null_checksum_refs_cb, NULL); + if (removed_refs > 0) + g_debug ("Removed %d refs from the list resolved from ‘%s’ (possibly bloom filter false positives)", + removed_refs, remote->name); + + /* If none of the refs had a non-%NULL checksum set, we can discard this peer. */ + if (g_hash_table_size (supported_ref_to_checksum) == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No matching refs were found in the summary file"); + return FALSE; + } + + return TRUE; +} + +/* Download the summary file from @remote, and return the bytes of the file in + * @out_summary_bytes. This will return %TRUE and set @out_summary_bytes to %NULL + * if the summary file does not exist. */ +static gboolean +fetch_summary_from_remote (OstreeRepo *repo, + OstreeRemote *remote, + GBytes **out_summary_bytes, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GBytes) summary_bytes = NULL; + gboolean remote_already_existed = _ostree_repo_add_remote (repo, remote); + gboolean success = ostree_repo_remote_fetch_summary_with_options (repo, + remote->name, + NULL /* options */, + &summary_bytes, + NULL /* signature */, + cancellable, + error); + + if (!remote_already_existed) + _ostree_repo_remove_remote (repo, remote); + + if (!success) + return FALSE; + + g_assert (out_summary_bytes != NULL); + *out_summary_bytes = g_steal_pointer (&summary_bytes); + return TRUE; +} +#endif /* HAVE_AVAHI */ + +struct _OstreeRepoFinderAvahi +{ + GObject parent_instance; + +#ifdef HAVE_AVAHI + /* All elements of this structure must only be accessed from @avahi_context + * after construction. */ + + /* Note: There is a ref-count loop here: each #GTask has a reference to the + * #OstreeRepoFinderAvahi, and we have to keep a reference to the #GTask. */ + GPtrArray *resolve_tasks; /* (element-type (owned) GTask) */ + + AvahiGLibPoll *poll; + AvahiClient *client; + AvahiServiceBrowser *browser; + + AvahiClientState client_state; + gboolean browser_failed; + gboolean browser_all_for_now; + + GCancellable *avahi_cancellable; + GMainContext *avahi_context; + + /* Map of service name (typically human readable) to a #GPtrArray of the + * #AvahiServiceResolver instances we have running against that name. We + * could end up with more than one resolver if the same name is advertised to + * us over multiple interfaces or protocols (for example, IPv4 and IPv6). + * Resolve all of them just in case one doesn’t work. */ + GHashTable *resolvers; /* (element-type (owned) utf8 (owned) GPtrArray (element-type (owned) AvahiServiceResolver)) */ + + /* Array of #OstreeAvahiService instances representing all the services which + * we currently think are valid. */ + GPtrArray *found_services; /* (element-type (owned OstreeAvahiService) */ +#endif /* HAVE_AVAHI */ +}; + +static void ostree_repo_finder_avahi_iface_init (OstreeRepoFinderInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (OstreeRepoFinderAvahi, ostree_repo_finder_avahi, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_REPO_FINDER, ostree_repo_finder_avahi_iface_init)) + +#ifdef HAVE_AVAHI + +/* Download the summary file from @remote and fill in the checksums in the given + * @supported_ref_to_checksum hash table, given the existing refs in it as keys. + * See get_refs_and_checksums_from_summary() for more details. */ +static gboolean +get_checksums (OstreeRepoFinderAvahi *finder, + OstreeRepo *repo, + OstreeRemote *remote, + GHashTable *supported_ref_to_checksum /* (element-type OstreeCollectionRef utf8) */, + GError **error) +{ + g_autoptr(GBytes) summary_bytes = NULL; + + if (!fetch_summary_from_remote (repo, + remote, + &summary_bytes, + finder->avahi_cancellable, + error)) + return FALSE; + + if (summary_bytes == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No summary file found on server"); + return FALSE; + } + + return get_refs_and_checksums_from_summary (summary_bytes, supported_ref_to_checksum, remote, error); +} + +/* Build some #OstreeRepoFinderResults out of the given #OstreeAvahiService by + * parsing its DNS-SD TXT records and finding the intersection between the refs + * it advertises and @refs. One or more results will be added to @results, with + * multiple results being added if the intersection of refs covers refs which + * need different GPG keyrings. One result is added per (uri, keyring) pair. + * + * If any of the TXT records are malformed or missing, or if the intersection of + * refs is empty, return early without modifying @results. + * + * This recognises the following TXT records: + * - `v` (`y`): Version of the TXT record format. Only version `1` is currently + * supported. + * - `rb` (`(yyay)`): Bloom filter indicating which refs are served by the peer. + * - `st` (`t`): Timestamp (seconds since the Unix epoch, big endian) the + * summary file was last modified. + * - `ri` (`q`): Repository index, indicating which of several repositories + * hosted on the peer this is. Big endian. + */ +static void +ostree_avahi_service_build_repo_finder_result (OstreeAvahiService *service, + OstreeRepoFinderAvahi *finder, + OstreeRepo *parent_repo, + gint priority, + const OstreeCollectionRef * const *refs, + GPtrArray *results, + GCancellable *cancellable) +{ + g_autoptr(GHashTable) attributes = NULL; + g_autoptr(GVariant) version = NULL; + g_autoptr(GVariant) bloom = NULL; + g_autoptr(GVariant) summary_timestamp = NULL; + g_autoptr(GVariant) repo_index = NULL; + g_autofree gchar *repo_path = NULL; + g_autoptr(GPtrArray) possible_refs = NULL; /* (element-type OstreeCollectionRef) */ + SoupURI *_uri = NULL; + g_autofree gchar *uri = NULL; + g_autoptr(GError) error = NULL; + gsize i; + g_autoptr(GHashTable) repo_to_refs = NULL; /* (element-type UriAndKeyring GHashTable) */ + GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */ + GHashTableIter iter; + UriAndKeyring *repo; + + g_return_if_fail (service != NULL); + g_return_if_fail (refs != NULL); + + attributes = _ostree_txt_records_parse (service->txt); + + /* Check the record version. */ + version = _ostree_txt_records_lookup_variant (attributes, "v", G_VARIANT_TYPE_BYTE); + + if (g_variant_get_byte (version) != 1) + { + g_debug ("Unknown v=%02x attribute provided in TXT record. Ignoring.", + g_variant_get_byte (version)); + return; + } + + /* Refs bloom filter? */ + bloom = _ostree_txt_records_lookup_variant (attributes, "rb", G_VARIANT_TYPE ("(yyay)")); + + if (bloom == NULL) + { + g_debug ("Missing rb (refs bloom) attribute in TXT record. Ignoring."); + return; + } + + possible_refs = bloom_refs_intersection (bloom, refs); + if (possible_refs == NULL) + { + g_debug ("Wrong k parameter or hash id in rb (refs bloom) attribute in TXT record. Ignoring."); + return; + } + if (possible_refs->len == 0) + { + g_debug ("TXT record definitely has no matching refs. Ignoring."); + return; + } + + /* Summary timestamp. */ + summary_timestamp = _ostree_txt_records_lookup_variant (attributes, "st", G_VARIANT_TYPE_UINT64); + if (summary_timestamp == NULL) + { + g_debug ("Missing st (summary timestamp) attribute in TXT record. Ignoring."); + return; + } + + /* Repository index. */ + repo_index = _ostree_txt_records_lookup_variant (attributes, "ri", G_VARIANT_TYPE_UINT16); + if (repo_index == NULL) + { + g_debug ("Missing ri (repository index) attribute in TXT record. Ignoring."); + return; + } + repo_path = g_strdup_printf ("/%u", GUINT16_FROM_BE (g_variant_get_uint16 (repo_index))); + + /* Create a new result for each keyring needed by @possible_refs. Typically, + * there will be a separate keyring per collection, but some might be shared. */ + repo_to_refs = g_hash_table_new_full (uri_and_keyring_hash, uri_and_keyring_equal, + (GDestroyNotify) uri_and_keyring_free, (GDestroyNotify) g_hash_table_unref); + + _uri = soup_uri_new (NULL); + soup_uri_set_scheme (_uri, "http"); + soup_uri_set_host (_uri, service->address); + soup_uri_set_port (_uri, service->port); + soup_uri_set_path (_uri, repo_path); + uri = soup_uri_to_string (_uri, FALSE); + soup_uri_free (_uri); + + for (i = 0; i < possible_refs->len; i++) + { + const OstreeCollectionRef *ref = g_ptr_array_index (possible_refs, i); + g_autoptr(UriAndKeyring) resolved_repo = NULL; + g_autoptr(OstreeRemote) keyring_remote = NULL; + + /* Look up the GPG keyring for this ref. */ + keyring_remote = ostree_repo_resolve_keyring_for_collection (parent_repo, + ref->collection_id, + cancellable, &error); + + if (keyring_remote == NULL) + { + g_debug ("Ignoring ref (%s, %s) on host ‘%s’ due to missing keyring: %s", + ref->collection_id, refs[i]->ref_name, service->address, + error->message); + g_clear_error (&error); + continue; + } + + /* Add this repo to the results, keyed by the canonicalised repository URI + * to deduplicate the results. */ + g_debug ("Resolved ref (%s, %s) to repo URI ‘%s’ with keyring ‘%s’ from remote ‘%s’.", + ref->collection_id, ref->ref_name, uri, keyring_remote->keyring, + keyring_remote->name); + + resolved_repo = uri_and_keyring_new (uri, keyring_remote); + + supported_ref_to_checksum = g_hash_table_lookup (repo_to_refs, resolved_repo); + + if (supported_ref_to_checksum == NULL) + { + supported_ref_to_checksum = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + NULL, g_free); + g_hash_table_insert (repo_to_refs, g_steal_pointer (&resolved_repo), supported_ref_to_checksum /* transfer */); + } + + /* Add a placeholder to @supported_ref_to_checksum for this ref. It will + * be filled out by the get_checksums() call below. */ + g_hash_table_insert (supported_ref_to_checksum, (gpointer) ref, NULL); + } + + /* Aggregate the results. */ + g_hash_table_iter_init (&iter, repo_to_refs); + + while (g_hash_table_iter_next (&iter, (gpointer *) &repo, (gpointer *) &supported_ref_to_checksum)) + { + g_autoptr(OstreeRemote) remote = NULL; + + /* Build an #OstreeRemote. Use the escaped URI, since remote->name + * is used in file paths, so needs to not contain special characters. */ + g_autofree gchar *name = uri_and_keyring_to_name (repo); + remote = ostree_remote_new_dynamic (name, repo->keyring_remote->name); + + g_clear_pointer (&remote->keyring, g_free); + remote->keyring = g_strdup (repo->keyring_remote->keyring); + + /* gpg-verify-summary is false since we use the unsigned summary file support. */ + g_key_file_set_string (remote->options, remote->group, "url", repo->uri); + g_key_file_set_boolean (remote->options, remote->group, "gpg-verify", TRUE); + g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", FALSE); + + get_checksums (finder, parent_repo, remote, supported_ref_to_checksum, &error); + if (error != NULL) + { + g_debug ("Failed to get checksums for possible refs; ignoring: %s", error->message); + g_clear_error (&error); + continue; + } + + g_ptr_array_add (results, ostree_repo_finder_result_new (remote, OSTREE_REPO_FINDER (finder), + priority, supported_ref_to_checksum, NULL, + GUINT64_FROM_BE (g_variant_get_uint64 (summary_timestamp)))); + } +} + +typedef struct +{ + OstreeCollectionRef **refs; /* (owned) (array zero-terminated=1) */ + OstreeRepo *parent_repo; /* (owned) */ +} ResolveData; + +static void +resolve_data_free (ResolveData *data) +{ + g_object_unref (data->parent_repo); + ostree_collection_ref_freev (data->refs); + g_free (data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (ResolveData, resolve_data_free) + +static ResolveData * +resolve_data_new (const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo) +{ + g_autoptr(ResolveData) data = NULL; + + data = g_new0 (ResolveData, 1); + data->refs = ostree_collection_ref_dupv (refs); + data->parent_repo = g_object_ref (parent_repo); + + return g_steal_pointer (&data); +} + +static void +fail_all_pending_tasks (OstreeRepoFinderAvahi *self, + GQuark domain, + gint code, + const gchar *format, + ...) G_GNUC_PRINTF(4, 5); + +/* Executed in @self->avahi_context. + * + * Return the given error from all the pending resolve tasks in + * self->resolve_tasks. */ +static void +fail_all_pending_tasks (OstreeRepoFinderAvahi *self, + GQuark domain, + gint code, + const gchar *format, + ...) +{ + gsize i; + va_list args; + g_autoptr(GError) error = NULL; + + g_assert (g_main_context_is_owner (self->avahi_context)); + + va_start (args, format); + error = g_error_new_valist (domain, code, format, args); + va_end (args); + + for (i = 0; i < self->resolve_tasks->len; i++) + { + GTask *task = G_TASK (g_ptr_array_index (self->resolve_tasks, i)); + g_task_return_error (task, g_error_copy (error)); + } + + g_ptr_array_set_size (self->resolve_tasks, 0); +} + +static gint +results_compare_cb (gconstpointer a, + gconstpointer b) +{ + const OstreeRepoFinderResult *result_a = *((const OstreeRepoFinderResult **) a); + const OstreeRepoFinderResult *result_b = *((const OstreeRepoFinderResult **) b); + + return ostree_repo_finder_result_compare (result_a, result_b); +} + +/* Executed in @self->avahi_context. + * + * For each of the pending resolve tasks in self->resolve_tasks, calculate and + * return the result set for its query given the currently known services from + * Avahi which are stored in self->found_services. */ +static void +complete_all_pending_tasks (OstreeRepoFinderAvahi *self) +{ + gsize i; + const gint priority = 60; /* arbitrarily chosen */ + g_autoptr(GPtrArray) results_for_tasks = g_ptr_array_new_full (self->resolve_tasks->len, (GDestroyNotify)g_ptr_array_unref); + gboolean cancelled = FALSE; + + g_assert (g_main_context_is_owner (self->avahi_context)); + g_debug ("%s: Completing %u tasks", G_STRFUNC, self->resolve_tasks->len); + + for (i = 0; i < self->resolve_tasks->len; i++) + { + g_autoptr(GPtrArray) results = NULL; + GTask *task; + ResolveData *data; + const OstreeCollectionRef * const *refs; + gsize j; + + task = G_TASK (g_ptr_array_index (self->resolve_tasks, i)); + data = g_task_get_task_data (task); + refs = (const OstreeCollectionRef * const *) data->refs; + results = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_repo_finder_result_free); + + for (j = 0; j < self->found_services->len; j++) + { + OstreeAvahiService *service = g_ptr_array_index (self->found_services, j); + + ostree_avahi_service_build_repo_finder_result (service, self, data->parent_repo, + priority, refs, results, + self->avahi_cancellable); + if (g_cancellable_is_cancelled (self->avahi_cancellable)) + { + cancelled = TRUE; + break; + } + } + if (cancelled) + break; + + g_ptr_array_add (results_for_tasks, g_steal_pointer (&results)); + } + + if (!cancelled) + { + for (i = 0; i < self->resolve_tasks->len; i++) + { + GTask *task = G_TASK (g_ptr_array_index (self->resolve_tasks, i)); + GPtrArray *results = g_ptr_array_index (results_for_tasks, i); + + g_ptr_array_sort (results, results_compare_cb); + + g_task_return_pointer (task, + g_ptr_array_ref (results), + (GDestroyNotify) g_ptr_array_unref); + } + + g_ptr_array_set_size (self->resolve_tasks, 0); + } + else + { + fail_all_pending_tasks (self, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "Avahi service resolution cancelled."); + } +} + +/* Executed in @self->avahi_context. */ +static void +maybe_complete_all_pending_tasks (OstreeRepoFinderAvahi *self) +{ + g_assert (g_main_context_is_owner (self->avahi_context)); + g_debug ("%s: client_state: %s, browser_failed: %u, cancelled: %u, " + "browser_all_for_now: %u, n_resolvers: %u", + G_STRFUNC, ostree_avahi_client_state_to_string (self->client_state), + self->browser_failed, + g_cancellable_is_cancelled (self->avahi_cancellable), + self->browser_all_for_now, g_hash_table_size (self->resolvers)); + + if (self->client_state == AVAHI_CLIENT_FAILURE) + fail_all_pending_tasks (self, G_IO_ERROR, G_IO_ERROR_FAILED, + "Avahi client error: %s", + avahi_strerror (avahi_client_errno (self->client))); + else if (self->browser_failed) + fail_all_pending_tasks (self, G_IO_ERROR, G_IO_ERROR_FAILED, + "Avahi browser error: %s", + avahi_strerror (avahi_client_errno (self->client))); + else if (g_cancellable_is_cancelled (self->avahi_cancellable)) + fail_all_pending_tasks (self, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "Avahi service resolution cancelled."); + else if (self->browser_all_for_now && + g_hash_table_size (self->resolvers) == 0) + complete_all_pending_tasks (self); +} + +/* Executed in @self->avahi_context. */ +static void +client_cb (AvahiClient *client, + AvahiClientState state, + void *finder_ptr) +{ + /* Completing the pending tasks might drop the final reference to @self. */ + g_autoptr(OstreeRepoFinderAvahi) self = g_object_ref (finder_ptr); + + /* self->client will be NULL if client_cb() is called from + * ostree_repo_finder_avahi_start(). */ + g_assert (self->client == NULL || g_main_context_is_owner (self->avahi_context)); + + g_debug ("%s: Entered state ‘%s’.", + G_STRFUNC, ostree_avahi_client_state_to_string (state)); + + /* We only care about entering and leaving %AVAHI_CLIENT_FAILURE. */ + self->client_state = state; + if (self->client != NULL) + maybe_complete_all_pending_tasks (self); +} + +/* Executed in @self->avahi_context. */ +static void +resolve_cb (AvahiServiceResolver *resolver, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void *finder_ptr) +{ + /* Completing the pending tasks might drop the final reference to @self. */ + g_autoptr(OstreeRepoFinderAvahi) self = g_object_ref (finder_ptr); + g_autoptr(OstreeAvahiService) service = NULL; + GPtrArray *resolvers; + + g_assert (g_main_context_is_owner (self->avahi_context)); + + g_debug ("%s: Resolve event ‘%s’ for name ‘%s’.", + G_STRFUNC, ostree_avahi_resolver_event_to_string (event), name); + + /* Track the resolvers active for this @name. There may be several, + * as @name might appear to us over several interfaces or protocols. Most + * commonly this happens when both hosts are connected via IPv4 and IPv6. */ + resolvers = g_hash_table_lookup (self->resolvers, name); + + if (resolvers == NULL || resolvers->len == 0) + { + /* maybe it was removed in the meantime */ + g_hash_table_remove (self->resolvers, name); + return; + } + else if (resolvers->len == 1) + { + g_hash_table_remove (self->resolvers, name); + } + else + { + g_ptr_array_remove_fast (resolvers, resolver); + } + + /* Was resolution successful? */ + switch (event) + { + case AVAHI_RESOLVER_FOUND: + service = ostree_avahi_service_new (name, domain, address, interface, + port, txt); + g_ptr_array_add (self->found_services, g_steal_pointer (&service)); + break; + case AVAHI_RESOLVER_FAILURE: + default: + g_warning ("Failed to resolve service ‘%s’: %s", name, + avahi_strerror (avahi_client_errno (self->client))); + break; + } + + maybe_complete_all_pending_tasks (self); +} + +/* Executed in @self->avahi_context. */ +static void +browse_new (OstreeRepoFinderAvahi *self, + AvahiIfIndex interface, + AvahiProtocol protocol, + const gchar *name, + const gchar *type, + const gchar *domain) +{ + g_autoptr(AvahiServiceResolver) resolver = NULL; + GPtrArray *resolvers; /* (element-type AvahiServiceResolver) */ + + g_assert (g_main_context_is_owner (self->avahi_context)); + + resolver = avahi_service_resolver_new (self->client, + interface, + protocol, + name, + type, + domain, + AVAHI_PROTO_UNSPEC, + 0, + resolve_cb, + self); + if (resolver == NULL) + { + g_warning ("Failed to resolve service ‘%s’: %s", name, + avahi_strerror (avahi_client_errno (self->client))); + return; + } + + g_debug ("Found name service %s on the network; type: %s, domain: %s, " + "protocol: %u, interface: %u", name, type, domain, protocol, + interface); + + /* Start a resolver for this (interface, protocol, name, type, domain) + * combination. */ + resolvers = g_hash_table_lookup (self->resolvers, name); + if (resolvers == NULL) + { + resolvers = g_ptr_array_new_with_free_func ((GDestroyNotify) avahi_service_resolver_free); + g_hash_table_insert (self->resolvers, g_strdup (name), resolvers); + } + + g_ptr_array_add (resolvers, g_steal_pointer (&resolver)); +} + +/* Executed in @self->avahi_context. Caller must call maybe_complete_all_pending_tasks(). */ +static void +browse_remove (OstreeRepoFinderAvahi *self, + const char *name) +{ + gsize i; + gboolean removed = FALSE; + + g_assert (g_main_context_is_owner (self->avahi_context)); + + g_hash_table_remove (self->resolvers, name); + + for (i = 0; i < self->found_services->len; i += (removed ? 0 : 1)) + { + OstreeAvahiService *service = g_ptr_array_index (self->found_services, i); + + removed = FALSE; + + if (g_strcmp0 (service->name, name) == 0) + { + g_ptr_array_remove_index_fast (self->found_services, i); + removed = TRUE; + continue; + } + } +} + +/* Executed in @self->avahi_context. */ +static void +browse_cb (AvahiServiceBrowser *browser, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, + const char *type, + const char *domain, + AvahiLookupResultFlags flags, + void *finder_ptr) +{ + /* Completing the pending tasks might drop the final reference to @self. */ + g_autoptr(OstreeRepoFinderAvahi) self = g_object_ref (finder_ptr); + + g_assert (g_main_context_is_owner (self->avahi_context)); + + g_debug ("%s: Browse event ‘%s’ for name ‘%s’.", + G_STRFUNC, ostree_avahi_browser_event_to_string (event), name); + + self->browser_failed = FALSE; + + switch (event) + { + case AVAHI_BROWSER_NEW: + browse_new (self, interface, protocol, name, type, domain); + break; + + case AVAHI_BROWSER_REMOVE: + browse_remove (self, name); + break; + + case AVAHI_BROWSER_CACHE_EXHAUSTED: + /* don’t care about this. */ + break; + + case AVAHI_BROWSER_ALL_FOR_NOW: + self->browser_all_for_now = TRUE; + break; + + case AVAHI_BROWSER_FAILURE: + self->browser_failed = TRUE; + break; + + default: + g_assert_not_reached (); + } + + /* Check all the tasks for any event, since the @browser_failed state + * may have changed. */ + maybe_complete_all_pending_tasks (self); +} + +static gboolean add_resolve_task_cb (gpointer user_data); +#endif /* HAVE_AVAHI */ + +static void +ostree_repo_finder_avahi_resolve_async (OstreeRepoFinder *finder, + const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + OstreeRepoFinderAvahi *self = OSTREE_REPO_FINDER_AVAHI (finder); + g_autoptr(GTask) task = NULL; + + g_debug ("%s: Starting resolving", G_STRFUNC); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, ostree_repo_finder_avahi_resolve_async); + +#ifdef HAVE_AVAHI + g_task_set_task_data (task, resolve_data_new (refs, parent_repo), (GDestroyNotify) resolve_data_free); + + /* Move @task to the @avahi_context where it can be processed. */ + g_main_context_invoke (self->avahi_context, add_resolve_task_cb, g_steal_pointer (&task)); +#else /* if !HAVE_AVAHI */ + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Avahi support was not compiled in to libostree"); +#endif /* !HAVE_AVAHI */ +} + +#ifdef HAVE_AVAHI +/* Executed in @self->avahi_context. */ +static gboolean +add_resolve_task_cb (gpointer user_data) +{ + g_autoptr(GTask) task = G_TASK (user_data); + OstreeRepoFinderAvahi *self = g_task_get_source_object (task); + + g_assert (g_main_context_is_owner (self->avahi_context)); + g_debug ("%s", G_STRFUNC); + + /* Track the task and check to see if the browser and resolvers are in a + * quiescent state suitable for returning a result immediately. */ + g_ptr_array_add (self->resolve_tasks, g_object_ref (task)); + maybe_complete_all_pending_tasks (self); + + return G_SOURCE_REMOVE; +} +#endif /* HAVE_AVAHI */ + +static GPtrArray * +ostree_repo_finder_avahi_resolve_finish (OstreeRepoFinder *finder, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, finder), NULL); + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +ostree_repo_finder_avahi_dispose (GObject *obj) +{ +#ifdef HAVE_AVAHI + OstreeRepoFinderAvahi *self = OSTREE_REPO_FINDER_AVAHI (obj); + + ostree_repo_finder_avahi_stop (self); + + g_assert (self->resolve_tasks == NULL || self->resolve_tasks->len == 0); + + g_clear_pointer (&self->resolve_tasks, g_ptr_array_unref); + g_clear_pointer (&self->browser, avahi_service_browser_free); + g_clear_pointer (&self->client, avahi_client_free); + g_clear_pointer (&self->poll, avahi_glib_poll_free); + g_clear_pointer (&self->avahi_context, g_main_context_unref); + g_clear_pointer (&self->found_services, g_ptr_array_unref); + g_clear_pointer (&self->resolvers, g_hash_table_unref); + g_clear_object (&self->avahi_cancellable); +#endif /* HAVE_AVAHI */ + + /* Chain up. */ + G_OBJECT_CLASS (ostree_repo_finder_avahi_parent_class)->dispose (obj); +} + +static void +ostree_repo_finder_avahi_class_init (OstreeRepoFinderAvahiClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = ostree_repo_finder_avahi_dispose; +} + +static void +ostree_repo_finder_avahi_iface_init (OstreeRepoFinderInterface *iface) +{ + iface->resolve_async = ostree_repo_finder_avahi_resolve_async; + iface->resolve_finish = ostree_repo_finder_avahi_resolve_finish; +} + +static void +ostree_repo_finder_avahi_init (OstreeRepoFinderAvahi *self) +{ +#ifdef HAVE_AVAHI + self->resolve_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + self->avahi_cancellable = g_cancellable_new (); + self->client_state = AVAHI_CLIENT_S_REGISTERING; + self->resolvers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); + self->found_services = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_avahi_service_free); +#endif /* HAVE_AVAHI */ +} + +/** + * ostree_repo_finder_avahi_new: + * @context: (transfer none) (nullable): a #GMainContext for processing Avahi + * events in, or %NULL to use the current thread-default + * + * Create a new #OstreeRepoFinderAvahi instance. It is intended that one such + * instance be created per process, and it be used to answer all resolution + * requests from #OstreeRepos. + * + * The calling code is responsible for ensuring that @context is iterated while + * the #OstreeRepoFinderAvahi is running (after ostree_repo_finder_avahi_start() + * is called). This may be done from any thread. + * + * If @context is %NULL, the current thread-default #GMainContext is used. + * + * Returns: (transfer full): a new #OstreeRepoFinderAvahi + * Since: 2018.6 + */ +OstreeRepoFinderAvahi * +ostree_repo_finder_avahi_new (GMainContext *context) +{ + g_autoptr(OstreeRepoFinderAvahi) finder = NULL; + + finder = g_object_new (OSTREE_TYPE_REPO_FINDER_AVAHI, NULL); + +#ifdef HAVE_AVAHI + /* FIXME: Make this a property */ + if (context != NULL) + finder->avahi_context = g_main_context_ref (context); + else + finder->avahi_context = g_main_context_ref_thread_default (); + + /* Avahi setup. Note: Technically the allocator is per-process state which we + * shouldn’t set here, but it’s probably fine. It’s unlikely that code which + * is using libostree is going to use an allocator which is not GLib, and + * *also* use Avahi API itself. */ + avahi_set_allocator (avahi_glib_allocator ()); + finder->poll = avahi_glib_poll_new (finder->avahi_context, G_PRIORITY_DEFAULT); +#endif /* HAVE_AVAHI */ + + return g_steal_pointer (&finder); +} + +/** + * ostree_repo_finder_avahi_start: + * @self: an #OstreeRepoFinderAvahi + * @error: return location for a #GError + * + * Start monitoring the local network for peers who are advertising OSTree + * repositories, using Avahi. In order for this to work, the #GMainContext + * passed to @self at construction time must be iterated (so it will typically + * be the global #GMainContext, or be a separate #GMainContext in a worker + * thread). + * + * This will return an error (%G_IO_ERROR_FAILED) if initialisation fails, or if + * Avahi support is not available (%G_IO_ERROR_NOT_SUPPORTED). In either case, + * the #OstreeRepoFinderAvahi instance is useless afterwards and should be + * destroyed. + * + * Call ostree_repo_finder_avahi_stop() to stop the repo finder. + * + * It is an error to call this function multiple times on the same + * #OstreeRepoFinderAvahi instance, or to call it after + * ostree_repo_finder_avahi_stop(). + * + * Since: 2018.6 + */ +void +ostree_repo_finder_avahi_start (OstreeRepoFinderAvahi *self, + GError **error) +{ + g_return_if_fail (OSTREE_IS_REPO_FINDER_AVAHI (self)); + g_return_if_fail (error == NULL || *error == NULL); + +#ifdef HAVE_AVAHI + g_autoptr(AvahiClient) client = NULL; + g_autoptr(AvahiServiceBrowser) browser = NULL; + int failure = 0; + + if (g_cancellable_set_error_if_cancelled (self->avahi_cancellable, error)) + return; + + g_assert (self->client == NULL); + + client = avahi_client_new (avahi_glib_poll_get (self->poll), 0, + client_cb, self, &failure); + + if (client == NULL) + { + if (failure == AVAHI_ERR_NO_DAEMON) + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Avahi daemon is not running: %s", + avahi_strerror (failure)); + else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to create finder client: %s", + avahi_strerror (failure)); + + return; + } + + /* Query for the OSTree DNS-SD service on the local network. */ + browser = avahi_service_browser_new (client, + AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + OSTREE_AVAHI_SERVICE_TYPE, + NULL, + 0, + browse_cb, + self); + + if (browser == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to create service browser: %s", + avahi_strerror (avahi_client_errno (client))); + return; + } + + /* Success. */ + self->client = g_steal_pointer (&client); + self->browser = g_steal_pointer (&browser); +#else /* if !HAVE_AVAHI */ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Avahi support was not compiled in to libostree"); +#endif /* !HAVE_AVAHI */ +} + +#ifdef HAVE_AVAHI +static gboolean stop_cb (gpointer user_data); +#endif /* HAVE_AVAHI */ + +/** + * ostree_repo_finder_avahi_stop: + * @self: an #OstreeRepoFinderAvahi + * + * Stop monitoring the local network for peers who are advertising OSTree + * repositories. If any resolve tasks (from ostree_repo_finder_resolve_async()) + * are in progress, they will be cancelled and will return %G_IO_ERROR_CANCELLED. + * + * Call ostree_repo_finder_avahi_start() to start the repo finder. + * + * It is an error to call this function multiple times on the same + * #OstreeRepoFinderAvahi instance, or to call it before + * ostree_repo_finder_avahi_start(). + * + * Since: 2018.6 + */ +void +ostree_repo_finder_avahi_stop (OstreeRepoFinderAvahi *self) +{ + g_return_if_fail (OSTREE_IS_REPO_FINDER_AVAHI (self)); + +#ifdef HAVE_AVAHI + if (self->browser == NULL) + return; + + g_main_context_invoke (self->avahi_context, stop_cb, g_object_ref (self)); +#endif /* HAVE_AVAHI */ +} + +#ifdef HAVE_AVAHI +static gboolean +stop_cb (gpointer user_data) +{ + g_autoptr(OstreeRepoFinderAvahi) self = OSTREE_REPO_FINDER_AVAHI (user_data); + + g_cancellable_cancel (self->avahi_cancellable); + maybe_complete_all_pending_tasks (self); + + g_clear_pointer (&self->browser, avahi_service_browser_free); + g_clear_pointer (&self->client, avahi_client_free); + g_hash_table_remove_all (self->resolvers); + + return G_SOURCE_REMOVE; +} +#endif /* HAVE_AVAHI */ diff --git a/src/libostree/ostree-repo-finder-avahi.h b/src/libostree/ostree-repo-finder-avahi.h new file mode 100644 index 0000000..f79b68b --- /dev/null +++ b/src/libostree/ostree-repo-finder-avahi.h @@ -0,0 +1,63 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "ostree-repo-finder.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_REPO_FINDER_AVAHI (ostree_repo_finder_avahi_get_type ()) + +/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44): +_OSTREE_PUBLIC +G_DECLARE_FINAL_TYPE (OstreeRepoFinderAvahi, ostree_repo_finder_avahi, OSTREE, REPO_FINDER_AVAHI, GObject) */ + +_OSTREE_PUBLIC +GType ostree_repo_finder_avahi_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeRepoFinderAvahi OstreeRepoFinderAvahi; +typedef struct { GObjectClass parent_class; } OstreeRepoFinderAvahiClass; + +static inline OstreeRepoFinderAvahi *OSTREE_REPO_FINDER_AVAHI (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_repo_finder_avahi_get_type (), OstreeRepoFinderAvahi); } +static inline gboolean OSTREE_IS_REPO_FINDER_AVAHI (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_repo_finder_avahi_get_type ()); } +G_GNUC_END_IGNORE_DEPRECATIONS + +_OSTREE_PUBLIC +OstreeRepoFinderAvahi *ostree_repo_finder_avahi_new (GMainContext *context); + +_OSTREE_PUBLIC +void ostree_repo_finder_avahi_start (OstreeRepoFinderAvahi *self, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_finder_avahi_stop (OstreeRepoFinderAvahi *self); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-finder-config.c b/src/libostree/ostree-repo-finder-config.c new file mode 100644 index 0000000..06f6165 --- /dev/null +++ b/src/libostree/ostree-repo-finder-config.c @@ -0,0 +1,243 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-remote-private.h" +#include "ostree-repo.h" +#include "ostree-repo-private.h" +#include "ostree-repo-finder.h" +#include "ostree-repo-finder-config.h" + +/** + * SECTION:ostree-repo-finder-config + * @title: OstreeRepoFinderConfig + * @short_description: Finds remote repositories from ref names using the local + * repository configuration files + * @stability: Unstable + * @include: libostree/ostree-repo-finder-config.h + * + * #OstreeRepoFinderConfig is an implementation of #OstreeRepoFinder which looks + * refs up in locally configured remotes and returns remote URIs. + * Duplicate remote URIs are combined into a single #OstreeRepoFinderResult + * which lists multiple refs. + * + * For all the locally configured remotes which have an `collection-id` specified + * (see [ostree.repo-config(5)](man:ostree.repo-config(5))), it finds the + * intersection of their refs and the set of refs to resolve. If the + * intersection is non-empty, that remote is returned as a result. Remotes which + * do not have their `collection-id` key configured are ignored. + * + * Since: 2018.6 + */ + +static void ostree_repo_finder_config_iface_init (OstreeRepoFinderInterface *iface); + +struct _OstreeRepoFinderConfig +{ + GObject parent_instance; +}; + +G_DEFINE_TYPE_WITH_CODE (OstreeRepoFinderConfig, ostree_repo_finder_config, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_REPO_FINDER, ostree_repo_finder_config_iface_init)) + +static gint +results_compare_cb (gconstpointer a, + gconstpointer b) +{ + const OstreeRepoFinderResult *result_a = *((const OstreeRepoFinderResult **) a); + const OstreeRepoFinderResult *result_b = *((const OstreeRepoFinderResult **) b); + + return ostree_repo_finder_result_compare (result_a, result_b); +} + +static void +ostree_repo_finder_config_resolve_async (OstreeRepoFinder *finder, + const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + g_autoptr(GPtrArray) results = NULL; + const gint priority = 100; /* arbitrarily chosen; lower than the others */ + gsize i, j; + g_autoptr(GHashTable) repo_name_to_refs = NULL; /* (element-type utf8 GHashTable) */ + GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */ + GHashTableIter iter; + const gchar *remote_name; + g_auto(GStrv) remotes = NULL; + guint n_remotes = 0; + + task = g_task_new (finder, cancellable, callback, user_data); + g_task_set_source_tag (task, ostree_repo_finder_config_resolve_async); + results = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_repo_finder_result_free); + repo_name_to_refs = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify) g_hash_table_unref); + + /* List all remotes in this #OstreeRepo and see which of their ref lists + * intersect with @refs. */ + remotes = ostree_repo_remote_list (parent_repo, &n_remotes); + + g_debug ("%s: Checking %u remotes", G_STRFUNC, n_remotes); + + for (i = 0; i < n_remotes; i++) + { + g_autoptr(GError) local_error = NULL; + g_autoptr(GHashTable) remote_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + const gchar *checksum; + g_autofree gchar *remote_collection_id = NULL; + gboolean resolved_a_ref = FALSE; + + remote_name = remotes[i]; + + if (!ostree_repo_get_remote_option (parent_repo, remote_name, "collection-id", + NULL, &remote_collection_id, &local_error) || + !ostree_validate_collection_id (remote_collection_id, &local_error)) + { + g_debug ("Ignoring remote ‘%s’ due to no valid collection ID being configured for it: %s", + remote_name, local_error->message); + g_clear_error (&local_error); + continue; + } + + if (!ostree_repo_remote_list_collection_refs (parent_repo, remote_name, + &remote_refs, cancellable, + &local_error)) + { + g_debug ("Ignoring remote ‘%s’ due to error loading its refs: %s", + remote_name, local_error->message); + g_clear_error (&local_error); + continue; + } + + for (j = 0; refs[j] != NULL; j++) + { + if (g_strcmp0 (refs[j]->collection_id, remote_collection_id) == 0 && + g_hash_table_lookup_extended (remote_refs, refs[j], NULL, (gpointer *) &checksum)) + { + /* The requested ref is listed in the refs for this remote. Add + * the remote to the results, and the ref to its + * @supported_ref_to_checksum. */ + g_debug ("Resolved ref (%s, %s) to remote ‘%s’.", + refs[j]->collection_id, refs[j]->ref_name, remote_name); + resolved_a_ref = TRUE; + + supported_ref_to_checksum = g_hash_table_lookup (repo_name_to_refs, remote_name); + + if (supported_ref_to_checksum == NULL) + { + supported_ref_to_checksum = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + NULL, g_free); + g_hash_table_insert (repo_name_to_refs, (gpointer) remote_name, supported_ref_to_checksum /* transfer */); + } + + g_hash_table_insert (supported_ref_to_checksum, + (gpointer) refs[j], g_strdup (checksum)); + } + } + + if (!resolved_a_ref) + g_debug ("Ignoring remote ‘%s’ due to it not advertising any of the requested refs.", remote_name); + } + + /* Aggregate the results. */ + g_hash_table_iter_init (&iter, repo_name_to_refs); + + while (g_hash_table_iter_next (&iter, (gpointer *) &remote_name, (gpointer *) &supported_ref_to_checksum)) + { + g_autoptr(GError) local_error = NULL; + g_autoptr(OstreeRemote) remote = NULL; + + /* We don’t know what last-modified timestamp the remote has without + * making expensive HTTP queries, so leave that information blank. We + * assume that the configuration which says the refs and commits in + * @supported_ref_to_checksum are in the repository is correct; the code + * in ostree_repo_find_remotes_async() will check that. */ + remote = _ostree_repo_get_remote_inherited (parent_repo, remote_name, &local_error); + if (remote == NULL) + { + g_debug ("Configuration for remote ‘%s’ could not be found. Ignoring.", + remote_name); + continue; + } + + g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0)); + } + + g_ptr_array_sort (results, results_compare_cb); + + g_task_return_pointer (task, g_steal_pointer (&results), (GDestroyNotify) g_ptr_array_unref); +} + +static GPtrArray * +ostree_repo_finder_config_resolve_finish (OstreeRepoFinder *finder, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, finder), NULL); + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +ostree_repo_finder_config_init (OstreeRepoFinderConfig *self) +{ + /* Nothing to see here. */ +} + +static void +ostree_repo_finder_config_class_init (OstreeRepoFinderConfigClass *klass) +{ + /* Nothing to see here. */ +} + +static void +ostree_repo_finder_config_iface_init (OstreeRepoFinderInterface *iface) +{ + iface->resolve_async = ostree_repo_finder_config_resolve_async; + iface->resolve_finish = ostree_repo_finder_config_resolve_finish; +} + +/** + * ostree_repo_finder_config_new: + * + * Create a new #OstreeRepoFinderConfig. + * + * Returns: (transfer full): a new #OstreeRepoFinderConfig + * Since: 2018.6 + */ +OstreeRepoFinderConfig * +ostree_repo_finder_config_new (void) +{ + return g_object_new (OSTREE_TYPE_REPO_FINDER_CONFIG, NULL); +} diff --git a/src/libostree/ostree-repo-finder-config.h b/src/libostree/ostree-repo-finder-config.h new file mode 100644 index 0000000..c508432 --- /dev/null +++ b/src/libostree/ostree-repo-finder-config.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "ostree-repo-finder.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_REPO_FINDER_CONFIG (ostree_repo_finder_config_get_type ()) + +/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44): +_OSTREE_PUBLIC +G_DECLARE_FINAL_TYPE (OstreeRepoFinderConfig, ostree_repo_finder_config, OSTREE, REPO_FINDER_CONFIG, GObject) */ + +_OSTREE_PUBLIC +GType ostree_repo_finder_config_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeRepoFinderConfig OstreeRepoFinderConfig; +typedef struct { GObjectClass parent_class; } OstreeRepoFinderConfigClass; + +static inline OstreeRepoFinderConfig *OSTREE_REPO_FINDER_CONFIG (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_repo_finder_config_get_type (), OstreeRepoFinderConfig); } +static inline gboolean OSTREE_IS_REPO_FINDER_CONFIG (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_repo_finder_config_get_type ()); } +G_GNUC_END_IGNORE_DEPRECATIONS + +_OSTREE_PUBLIC +OstreeRepoFinderConfig *ostree_repo_finder_config_new (void); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-finder-mount.c b/src/libostree/ostree-repo-finder-mount.c new file mode 100644 index 0000000..c259f3e --- /dev/null +++ b/src/libostree/ostree-repo-finder-mount.c @@ -0,0 +1,693 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-remote-private.h" +#include "ostree-repo-private.h" +#include "ostree-repo-finder.h" +#include "ostree-repo-finder-mount.h" + +/** + * SECTION:ostree-repo-finder-mount + * @title: OstreeRepoFinderMount + * @short_description: Finds remote repositories from ref names by looking at + * mounted removable volumes + * @stability: Unstable + * @include: libostree/ostree-repo-finder-mount.h + * + * #OstreeRepoFinderMount is an implementation of #OstreeRepoFinder which looks + * refs up in well-known locations on any mounted removable volumes. + * + * For each mounted removable volume, the directory `.ostree/repos.d` will be + * enumerated, and all OSTree repositories below it will be searched, in lexical + * order, for the requested #OstreeCollectionRefs. The names of the directories + * below `.ostree/repos.d` are irrelevant, apart from their lexical ordering. + * The directories `.ostree/repo`, `ostree/repo` and `var/lib/flatpak/repo` + * will be searched after the others, if they exist. + * Non-removable volumes are ignored. + * + * For each repository which is found, a result will be returned for the + * intersection of the refs being searched for, and the refs in `refs/heads` and + * `refs/mirrors` in the repository on the removable volume. + * + * Symlinks are followed when listing the repositories, so a volume might + * contain a single OSTree at some arbitrary path, with a symlink from + * `.ostree/repos.d`. Any symlink which points outside the volume’s file + * system will be ignored. Repositories are deduplicated in the results. + * + * The volume monitor used to find mounted volumes can be overridden by setting + * #OstreeRepoFinderMount:monitor. By default, g_volume_monitor_get() is used. + * + * Since: 2018.6 + */ + +typedef GList/**/ ObjectList; + +static void +object_list_free (ObjectList *list) +{ + g_list_free_full (list, g_object_unref); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (ObjectList, object_list_free) + +static void ostree_repo_finder_mount_iface_init (OstreeRepoFinderInterface *iface); + +struct _OstreeRepoFinderMount +{ + GObject parent_instance; + + GVolumeMonitor *monitor; /* owned */ +}; + +G_DEFINE_TYPE_WITH_CODE (OstreeRepoFinderMount, ostree_repo_finder_mount, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_REPO_FINDER, ostree_repo_finder_mount_iface_init)) + +typedef struct +{ + gchar *uri; + OstreeRemote *keyring_remote; /* (owned) */ +} UriAndKeyring; + +static void +uri_and_keyring_free (UriAndKeyring *data) +{ + g_free (data->uri); + ostree_remote_unref (data->keyring_remote); + g_free (data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (UriAndKeyring, uri_and_keyring_free) + +static UriAndKeyring * +uri_and_keyring_new (const gchar *uri, + OstreeRemote *keyring_remote) +{ + g_autoptr(UriAndKeyring) data = NULL; + + data = g_new0 (UriAndKeyring, 1); + data->uri = g_strdup (uri); + data->keyring_remote = ostree_remote_ref (keyring_remote); + + return g_steal_pointer (&data); +} + +static guint +uri_and_keyring_hash (gconstpointer key) +{ + const UriAndKeyring *_key = key; + + return g_str_hash (_key->uri) ^ g_str_hash (_key->keyring_remote->keyring); +} + +static gboolean +uri_and_keyring_equal (gconstpointer a, + gconstpointer b) +{ + const UriAndKeyring *_a = a, *_b = b; + + return (g_str_equal (_a->uri, _b->uri) && + g_str_equal (_a->keyring_remote->keyring, _b->keyring_remote->keyring)); +} + +/* This must return a valid remote name (suitable for use in a refspec). */ +static gchar * +uri_and_keyring_to_name (UriAndKeyring *data) +{ + g_autofree gchar *escaped_uri = g_uri_escape_string (data->uri, NULL, FALSE); + g_autofree gchar *escaped_keyring = g_uri_escape_string (data->keyring_remote->keyring, NULL, FALSE); + + /* FIXME: Need a better separator than `_`, since it’s not escaped in the input. */ + g_autofree gchar *out = g_strdup_printf ("%s_%s", escaped_uri, escaped_keyring); + + for (gsize i = 0; out[i] != '\0'; i++) + { + if (out[i] == '%') + out[i] = '_'; + } + + g_return_val_if_fail (ostree_validate_remote_name (out, NULL), NULL); + + return g_steal_pointer (&out); +} + +static gint +results_compare_cb (gconstpointer a, + gconstpointer b) +{ + const OstreeRepoFinderResult *result_a = *((const OstreeRepoFinderResult **) a); + const OstreeRepoFinderResult *result_b = *((const OstreeRepoFinderResult **) b); + + return ostree_repo_finder_result_compare (result_a, result_b); +} + +typedef struct +{ + char *ordering_name; /* (owned) */ + OstreeRepo *repo; /* (owned) */ + GHashTable *refs; /* (owned) (element-type OstreeCollectionRef utf8) */ +} RepoAndRefs; + +static void +repo_and_refs_clear (RepoAndRefs *data) +{ + g_hash_table_unref (data->refs); + g_object_unref (data->repo); + g_free (data->ordering_name); +} + +static gint +repo_and_refs_compare (gconstpointer a, + gconstpointer b) +{ + const RepoAndRefs *_a = a; + const RepoAndRefs *_b = b; + + return strcmp (_a->ordering_name, _b->ordering_name); +} + +/* Check whether the repo at @dfd/@path is within the given mount, is not equal + * to the @parent_repo, and can be opened. If so, return it as @out_repo and + * all its collection–refs as @out_refs, to be added into the results. */ +static gboolean +scan_repo (int dfd, + const char *path, + const char *mount_name, + const struct stat *mount_root_stbuf, + OstreeRepo *parent_repo, + OstreeRepo **out_repo, + GHashTable **out_refs, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GError) local_error = NULL; + + g_autoptr(OstreeRepo) repo = ostree_repo_open_at (dfd, path, cancellable, &local_error); + if (repo == NULL) + { + g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as it could not be opened: %s", + path, mount_name, local_error->message); + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + int repo_dfd = ostree_repo_get_dfd (repo); + struct stat stbuf; + + if (!glnx_fstat (repo_dfd, &stbuf, &local_error)) + { + g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as querying its info failed: %s", + path, mount_name, local_error->message); + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + /* Check the resolved repository path is below the mount point. Do not + * allow ref symlinks to point somewhere outside of the mounted volume. */ + if (stbuf.st_dev != mount_root_stbuf->st_dev) + { + g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as it’s on a different file system from the mount", + path, mount_name); + return glnx_throw (error, "Repository is on a different file system from the mount"); + } + + /* Exclude repositories which resolve to @parent_repo. */ + if (stbuf.st_dev == parent_repo->device && + stbuf.st_ino == parent_repo->inode) + { + g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as it is the same as the one we are resolving", + path, mount_name); + return glnx_throw (error, "Repository is the same as the one we are resolving"); + } + + /* List the repo’s refs and return them. */ + g_autoptr(GHashTable) repo_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + + if (!ostree_repo_list_collection_refs (repo, NULL, &repo_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, + cancellable, &local_error)) + { + g_debug ("Ignoring repository ‘%s’ on mount ‘%s’ as its refs could not be listed: %s", + path, mount_name, local_error->message); + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + if (out_repo != NULL) + *out_repo = g_steal_pointer (&repo); + if (out_refs != NULL) + *out_refs = g_steal_pointer (&repo_refs); + + return TRUE; +} + +static void +scan_and_add_repo (int dfd, + const char *path, + gboolean sortable, + const char *mount_name, + const struct stat *mount_root_stbuf, + OstreeRepo *parent_repo, + GArray *inout_repos_refs, + GCancellable *cancellable) +{ + g_autoptr(GHashTable) repo_refs = NULL; + g_autoptr(OstreeRepo) repo = NULL; + + if (scan_repo (dfd, path, + mount_name, mount_root_stbuf, + parent_repo, &repo, &repo_refs, cancellable, NULL)) + { + RepoAndRefs val = { + sortable ? g_strdup (path) : NULL, + g_steal_pointer (&repo), + g_steal_pointer (&repo_refs) + }; + g_array_append_val (inout_repos_refs, val); + + g_debug ("%s: Adding repo ‘%s’ on mount ‘%s’ (%ssortable)", + G_STRFUNC, path, mount_name, sortable ? "" : "not "); + } +} + +static void +ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finder, + const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + OstreeRepoFinderMount *self = OSTREE_REPO_FINDER_MOUNT (finder); + g_autoptr(GTask) task = NULL; + g_autoptr(ObjectList) mounts = NULL; + g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */ + GList *l; + const gint priority = 50; /* arbitrarily chosen */ + + task = g_task_new (finder, cancellable, callback, user_data); + g_task_set_source_tag (task, ostree_repo_finder_mount_resolve_async); + + mounts = g_volume_monitor_get_mounts (self->monitor); + results = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_repo_finder_result_free); + + g_debug ("%s: Found %u mounts", G_STRFUNC, g_list_length (mounts)); + + for (l = mounts; l != NULL; l = l->next) + { + GMount *mount = G_MOUNT (l->data); + g_autofree gchar *mount_name = NULL; + g_autoptr(GFile) mount_root = NULL; + g_autofree gchar *mount_root_path = NULL; + glnx_autofd int mount_root_dfd = -1; + struct stat mount_root_stbuf; + glnx_autofd int repos_dfd = -1; + gsize i; + g_autoptr(GHashTable) repo_to_refs = NULL; /* (element-type UriAndKeyring GHashTable) */ + GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */ + GHashTableIter iter; + UriAndKeyring *repo; + g_autoptr(GError) local_error = NULL; + + mount_name = g_mount_get_name (mount); + + /* Check the mount’s general properties. */ + if (g_mount_is_shadowed (mount)) + { + g_debug ("Ignoring mount ‘%s’ as it’s shadowed.", mount_name); + continue; + } + + mount_root = g_mount_get_root (mount); + mount_root_path = g_file_get_path (mount_root); + + if (!glnx_opendirat (AT_FDCWD, mount_root_path, TRUE, &mount_root_dfd, &local_error)) + { + g_debug ("Ignoring mount ‘%s’ as ‘%s’ directory can’t be opened: %s", + mount_name, mount_root_path, local_error->message); + continue; + } + +#if GLIB_CHECK_VERSION(2, 55, 0) +G_GNUC_BEGIN_IGNORE_DEPRECATIONS /* remove once GLIB_VERSION_MAX_ALLOWED ≥ 2.56 */ + g_autoptr(GUnixMountEntry) mount_entry = g_unix_mount_at (mount_root_path, NULL); + + if (mount_entry != NULL && + (g_unix_is_system_fs_type (g_unix_mount_get_fs_type (mount_entry)) || + g_unix_is_system_device_path (g_unix_mount_get_device_path (mount_entry)))) + { + g_debug ("Ignoring mount ‘%s’ as its file system type (%s) or device " + "path (%s) indicate it’s a system mount.", + mount_name, g_unix_mount_get_fs_type (mount_entry), + g_unix_mount_get_device_path (mount_entry)); + continue; + } +G_GNUC_END_IGNORE_DEPRECATIONS +#endif /* GLib 2.56.0 */ + + /* stat() the mount root so we can later check whether the resolved + * repositories for individual refs are on the same device (to avoid the + * symlinks for them pointing outside the mount root). */ + if (!glnx_fstat (mount_root_dfd, &mount_root_stbuf, &local_error)) + { + g_debug ("Ignoring mount ‘%s’ as querying info of ‘%s’ failed: %s", + mount_name, mount_root_path, local_error->message); + continue; + } + + /* Check if it contains a .ostree/repos.d directory. If not, move on and + * try the other well-known subdirectories. */ + if (!glnx_opendirat (mount_root_dfd, ".ostree/repos.d", TRUE, &repos_dfd, NULL)) + repos_dfd = -1; + + /* List all the repositories in the repos.d directory. */ + /* (element-type GHashTable (element-type OstreeCollectionRef utf8)) */ + g_autoptr(GArray) repos_refs = g_array_new (FALSE, TRUE, sizeof (RepoAndRefs)); + g_array_set_clear_func (repos_refs, (GDestroyNotify) repo_and_refs_clear); + + GLnxDirFdIterator repos_iter; + + if (repos_dfd >= 0 && + !glnx_dirfd_iterator_init_at (repos_dfd, ".", TRUE, &repos_iter, &local_error)) + { + g_debug ("Error iterating over ‘%s/.ostree/repos.d’ directory in mount ‘%s’: %s", + mount_root_path, mount_name, local_error->message); + g_clear_error (&local_error); + /* don’t skip this mount as there’s still the ostree/repo directory to try */ + } + else if (repos_dfd >= 0) + { + while (TRUE) + { + struct dirent *repo_dent; + + if (!glnx_dirfd_iterator_next_dent (&repos_iter, &repo_dent, cancellable, &local_error)) + { + g_debug ("Error iterating over ‘%s/.ostree/repos.d’ directory in mount ‘%s’: %s", + mount_root_path, mount_name, local_error->message); + g_clear_error (&local_error); + /* don’t skip this mount as there’s still the ostree/repo directory to try */ + break; + } + + if (repo_dent == NULL) + break; + + /* Grab the set of collection–refs from the repo if we can open it. */ + scan_and_add_repo (repos_dfd, repo_dent->d_name, TRUE, + mount_name, &mount_root_stbuf, + parent_repo, repos_refs, cancellable); + } + } + + /* Sort the repos lexically. */ + g_array_sort (repos_refs, repo_and_refs_compare); + + /* Also check the well-known special-case directories in the mount. + * Add them after sorting, so they’re always last. + * NOTE: If you change these, update the man page. */ + const gchar * const well_known_repos[] = + { + ".ostree/repo", + "ostree/repo", + "var/lib/flatpak/repo", + }; + + for (i = 0; i < G_N_ELEMENTS (well_known_repos); i++) + scan_and_add_repo (mount_root_dfd, well_known_repos[i], FALSE, + mount_name, &mount_root_stbuf, + parent_repo, repos_refs, cancellable); + + /* Check whether a subdirectory exists for any of the @refs we’re looking + * for. If so, and it’s a symbolic link, dereference it so multiple links + * to the same repository (containing multiple refs) are coalesced. + * Otherwise, include it as a result by itself. */ + repo_to_refs = g_hash_table_new_full (uri_and_keyring_hash, uri_and_keyring_equal, + (GDestroyNotify) uri_and_keyring_free, (GDestroyNotify) g_hash_table_unref); + + for (i = 0; refs[i] != NULL; i++) + { + const OstreeCollectionRef *ref = refs[i]; + g_autofree gchar *resolved_repo_uri = NULL; + g_autoptr(UriAndKeyring) resolved_repo = NULL; + + for (gsize j = 0; j < repos_refs->len; j++) + { + const RepoAndRefs *repo_and_refs = &g_array_index (repos_refs, RepoAndRefs, j); + OstreeRepo *repo = repo_and_refs->repo; + GHashTable *repo_refs = repo_and_refs->refs; + g_autofree char *repo_path = g_file_get_path (ostree_repo_get_path (repo)); + g_autoptr(OstreeRemote) keyring_remote = NULL; + + const gchar *checksum = g_hash_table_lookup (repo_refs, ref); + + if (checksum == NULL) + { + g_debug ("Ignoring repository ‘%s’ when looking for ref (%s, %s) on mount ‘%s’ as it doesn’t contain the ref.", + repo_path, ref->collection_id, ref->ref_name, mount_name); + g_clear_error (&local_error); + continue; + } + + /* Finally, look up the GPG keyring for this ref. */ + keyring_remote = ostree_repo_resolve_keyring_for_collection (parent_repo, + ref->collection_id, + cancellable, &local_error); + + if (keyring_remote == NULL) + { + g_debug ("Ignoring repository ‘%s’ when looking for ref (%s, %s) on mount ‘%s’ due to missing keyring: %s", + repo_path, ref->collection_id, ref->ref_name, mount_name, local_error->message); + g_clear_error (&local_error); + continue; + } + + /* There is a valid repo at (or pointed to by) + * $mount_root/.ostree/repos.d/$something. + * Add it to the results, keyed by the canonicalised repository URI + * to deduplicate the results. */ + g_autofree char *canonical_repo_path = realpath (repo_path, NULL); + resolved_repo_uri = g_strconcat ("file://", canonical_repo_path, NULL); + g_debug ("Resolved ref (%s, %s) on mount ‘%s’ to repo URI ‘%s’ with keyring ‘%s’ from remote ‘%s’.", + ref->collection_id, ref->ref_name, mount_name, resolved_repo_uri, + keyring_remote->keyring, keyring_remote->name); + + resolved_repo = uri_and_keyring_new (resolved_repo_uri, keyring_remote); + + supported_ref_to_checksum = g_hash_table_lookup (repo_to_refs, resolved_repo); + + if (supported_ref_to_checksum == NULL) + { + supported_ref_to_checksum = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + NULL, g_free); + g_hash_table_insert (repo_to_refs, g_steal_pointer (&resolved_repo), supported_ref_to_checksum /* transfer */); + } + + g_hash_table_insert (supported_ref_to_checksum, (gpointer) ref, g_strdup (checksum)); + + /* We’ve found a result for this collection–ref. No point in checking + * the other repos on the mount, since pulling in parallel from them won’t help. */ + break; + } + } + + /* Aggregate the results. */ + g_hash_table_iter_init (&iter, repo_to_refs); + + while (g_hash_table_iter_next (&iter, (gpointer *) &repo, (gpointer *) &supported_ref_to_checksum)) + { + g_autoptr(OstreeRemote) remote = NULL; + + /* Build an #OstreeRemote. Use the escaped URI, since remote->name + * is used in file paths, so needs to not contain special characters. */ + g_autofree gchar *name = uri_and_keyring_to_name (repo); + remote = ostree_remote_new_dynamic (name, repo->keyring_remote->name); + + g_clear_pointer (&remote->keyring, g_free); + remote->keyring = g_strdup (repo->keyring_remote->keyring); + + /* gpg-verify-summary is false since we use the unsigned summary file support. */ + g_key_file_set_string (remote->options, remote->group, "url", repo->uri); + g_key_file_set_boolean (remote->options, remote->group, "gpg-verify", TRUE); + g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", FALSE); + + /* Set the timestamp in the #OstreeRepoFinderResult to 0 because + * the code in ostree_repo_pull_from_remotes_async() will be able to + * check it just as quickly as we can here; so don’t duplicate the + * code. */ + g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0)); + } + } + + g_ptr_array_sort (results, results_compare_cb); + + g_task_return_pointer (task, g_steal_pointer (&results), (GDestroyNotify) g_ptr_array_unref); +} + +static GPtrArray * +ostree_repo_finder_mount_resolve_finish (OstreeRepoFinder *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, self), NULL); + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +ostree_repo_finder_mount_init (OstreeRepoFinderMount *self) +{ + /* Nothing to see here. */ +} + +static void +ostree_repo_finder_mount_constructed (GObject *object) +{ + OstreeRepoFinderMount *self = OSTREE_REPO_FINDER_MOUNT (object); + + G_OBJECT_CLASS (ostree_repo_finder_mount_parent_class)->constructed (object); + + if (self->monitor == NULL) + self->monitor = g_volume_monitor_get (); +} + +typedef enum +{ + PROP_MONITOR = 1, +} OstreeRepoFinderMountProperty; + +static void +ostree_repo_finder_mount_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeRepoFinderMount *self = OSTREE_REPO_FINDER_MOUNT (object); + + switch ((OstreeRepoFinderMountProperty) property_id) + { + case PROP_MONITOR: + g_value_set_object (value, self->monitor); + break; + default: + g_assert_not_reached (); + } +} + +static void +ostree_repo_finder_mount_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeRepoFinderMount *self = OSTREE_REPO_FINDER_MOUNT (object); + + switch ((OstreeRepoFinderMountProperty) property_id) + { + case PROP_MONITOR: + /* Construct-only. */ + g_assert (self->monitor == NULL); + self->monitor = g_value_dup_object (value); + break; + default: + g_assert_not_reached (); + } +} + +static void +ostree_repo_finder_mount_dispose (GObject *object) +{ + OstreeRepoFinderMount *self = OSTREE_REPO_FINDER_MOUNT (object); + + g_clear_object (&self->monitor); + + G_OBJECT_CLASS (ostree_repo_finder_mount_parent_class)->dispose (object); +} + +static void +ostree_repo_finder_mount_class_init (OstreeRepoFinderMountClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = ostree_repo_finder_mount_get_property; + object_class->set_property = ostree_repo_finder_mount_set_property; + object_class->constructed = ostree_repo_finder_mount_constructed; + object_class->dispose = ostree_repo_finder_mount_dispose; + + /** + * OstreeRepoFinderMount:monitor: + * + * Volume monitor to use to look up mounted volumes when queried. + * + * Since: 2018.6 + */ + g_object_class_install_property (object_class, PROP_MONITOR, + g_param_spec_object ("monitor", + "Volume Monitor", + "Volume monitor to use " + "to look up mounted " + "volumes when queried.", + G_TYPE_VOLUME_MONITOR, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +static void +ostree_repo_finder_mount_iface_init (OstreeRepoFinderInterface *iface) +{ + iface->resolve_async = ostree_repo_finder_mount_resolve_async; + iface->resolve_finish = ostree_repo_finder_mount_resolve_finish; +} + +/** + * ostree_repo_finder_mount_new: + * @monitor: (nullable) (transfer none): volume monitor to use, or %NULL to use + * the system default + * + * Create a new #OstreeRepoFinderMount, using the given @monitor to look up + * volumes. If @monitor is %NULL, the monitor from g_volume_monitor_get() will + * be used. + * + * Returns: (transfer full): a new #OstreeRepoFinderMount + * Since: 2018.6 + */ +OstreeRepoFinderMount * +ostree_repo_finder_mount_new (GVolumeMonitor *monitor) +{ + g_return_val_if_fail (monitor == NULL || G_IS_VOLUME_MONITOR (monitor), NULL); + + return g_object_new (OSTREE_TYPE_REPO_FINDER_MOUNT, + "monitor", monitor, + NULL); +} diff --git a/src/libostree/ostree-repo-finder-mount.h b/src/libostree/ostree-repo-finder-mount.h new file mode 100644 index 0000000..6c78135 --- /dev/null +++ b/src/libostree/ostree-repo-finder-mount.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "ostree-repo-finder.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_REPO_FINDER_MOUNT (ostree_repo_finder_mount_get_type ()) + +/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44): +_OSTREE_PUBLIC +G_DECLARE_FINAL_TYPE (OstreeRepoFinderMount, ostree_repo_finder_mount, OSTREE, REPO_FINDER_MOUNT, GObject) */ + +_OSTREE_PUBLIC +GType ostree_repo_finder_mount_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeRepoFinderMount OstreeRepoFinderMount; +typedef struct { GObjectClass parent_class; } OstreeRepoFinderMountClass; + +static inline OstreeRepoFinderMount *OSTREE_REPO_FINDER_MOUNT (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_repo_finder_mount_get_type (), OstreeRepoFinderMount); } +static inline gboolean OSTREE_IS_REPO_FINDER_MOUNT (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_repo_finder_mount_get_type ()); } +G_GNUC_END_IGNORE_DEPRECATIONS + +_OSTREE_PUBLIC +OstreeRepoFinderMount *ostree_repo_finder_mount_new (GVolumeMonitor *monitor); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-finder-override.c b/src/libostree/ostree-repo-finder-override.c new file mode 100644 index 0000000..3219954 --- /dev/null +++ b/src/libostree/ostree-repo-finder-override.c @@ -0,0 +1,324 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-remote-private.h" +#include "ostree-repo.h" +#include "ostree-repo-private.h" +#include "ostree-repo-finder.h" +#include "ostree-repo-finder-override.h" + +/** + * SECTION:ostree-repo-finder-override + * @title: OstreeRepoFinderOverride + * @short_description: Finds remote repositories from a list of repository URIs + * @stability: Unstable + * @include: libostree/ostree-repo-finder-override.h + * + * #OstreeRepoFinderOverride is an implementation of #OstreeRepoFinder which + * looks refs up in a list of remotes given by their URI, and returns the URIs + * which contain the refs. Duplicate remote URIs are combined into a single + * #OstreeRepoFinderResult which lists multiple refs. + * + * Each result is given an #OstreeRepoFinderResult.priority value of 20, which + * ranks its results above those from the other default #OstreeRepoFinder + * implementations. + * + * Results can only be returned for a ref if a remote and keyring are configured + * locally for the collection ID of that ref, otherwise there would be no keys + * available to verify signatures on commits for that ref. + * + * This is intended to be used for user-provided overrides and testing software + * which uses #OstreeRepoFinder. For production use, #OstreeRepoFinderConfig is + * recommended instead. + * + * Since: 2018.6 + */ + +static void ostree_repo_finder_override_iface_init (OstreeRepoFinderInterface *iface); + +struct _OstreeRepoFinderOverride +{ + GObject parent_instance; + + GPtrArray *override_uris; /* (owned) (element-type utf8) */ +}; + +G_DEFINE_TYPE_WITH_CODE (OstreeRepoFinderOverride, ostree_repo_finder_override, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_REPO_FINDER, ostree_repo_finder_override_iface_init)) + +static gint +results_compare_cb (gconstpointer a, + gconstpointer b) +{ + const OstreeRepoFinderResult *result_a = *((const OstreeRepoFinderResult **) a); + const OstreeRepoFinderResult *result_b = *((const OstreeRepoFinderResult **) b); + + return ostree_repo_finder_result_compare (result_a, result_b); +} + +/* This must return a valid remote name (suitable for use in a refspec). */ +static gchar * +uri_and_keyring_to_name (const gchar *uri, + const gchar *keyring) +{ + g_autofree gchar *escaped_uri = g_uri_escape_string (uri, NULL, FALSE); + g_autofree gchar *escaped_keyring = g_uri_escape_string (keyring, NULL, FALSE); + + /* FIXME: Need a better separator than `_`, since it’s not escaped in the input. */ + g_autofree gchar *out = g_strdup_printf ("%s_%s", escaped_uri, escaped_keyring); + + for (gsize i = 0; out[i] != '\0'; i++) + { + if (out[i] == '%') + out[i] = '_'; + } + + g_return_val_if_fail (ostree_validate_remote_name (out, NULL), NULL); + + return g_steal_pointer (&out); +} + +/* Version of ostree_repo_remote_list_collection_refs() which takes an + * #OstreeRemote. */ +static gboolean +repo_remote_list_collection_refs (OstreeRepo *repo, + const gchar *remote_uri, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error) +{ + g_autofree gchar *name = uri_and_keyring_to_name (remote_uri, ""); + g_autoptr(OstreeRemote) remote = ostree_remote_new (name); + g_key_file_set_string (remote->options, remote->group, "url", remote_uri); + + gboolean remote_already_existed = _ostree_repo_add_remote (repo, remote); + gboolean success = ostree_repo_remote_list_collection_refs (repo, + remote->name, + out_all_refs, + cancellable, + error); + + if (!remote_already_existed) + _ostree_repo_remove_remote (repo, remote); + + return success; +} + +static void +ostree_repo_finder_override_resolve_async (OstreeRepoFinder *finder, + const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + OstreeRepoFinderOverride *self = OSTREE_REPO_FINDER_OVERRIDE (finder); + g_autoptr(GTask) task = NULL; + g_autoptr(GPtrArray) results = NULL; + const gint priority = 20; /* arbitrarily chosen; higher priority than the others */ + gsize i, j; + g_autoptr(GHashTable) repo_remote_to_refs = NULL; /* (element-type OstreeRemote GHashTable) */ + GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */ + GHashTableIter iter; + const gchar *remote_uri; + OstreeRemote *remote; + + task = g_task_new (finder, cancellable, callback, user_data); + g_task_set_source_tag (task, ostree_repo_finder_override_resolve_async); + results = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_repo_finder_result_free); + repo_remote_to_refs = g_hash_table_new_full (g_direct_hash, g_direct_equal, + (GDestroyNotify) ostree_remote_unref, + (GDestroyNotify) g_hash_table_unref); + + g_debug ("%s: Checking %u overrides", G_STRFUNC, self->override_uris->len); + + for (i = 0; i < self->override_uris->len; i++) + { + g_autoptr(GError) local_error = NULL; + g_autoptr(GHashTable) remote_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + const gchar *checksum; + gboolean resolved_a_ref = FALSE; + + remote_uri = self->override_uris->pdata[i]; + + if (!repo_remote_list_collection_refs (parent_repo, remote_uri, + &remote_refs, cancellable, + &local_error)) + { + g_debug ("Ignoring remote ‘%s’ due to error loading its refs: %s", + remote_uri, local_error->message); + g_clear_error (&local_error); + continue; + } + + for (j = 0; refs[j] != NULL; j++) + { + g_autoptr(OstreeRemote) keyring_remote = NULL; + + /* Look up the GPG keyring for this ref. */ + keyring_remote = ostree_repo_resolve_keyring_for_collection (parent_repo, + refs[j]->collection_id, + cancellable, &local_error); + + if (keyring_remote == NULL) + { + g_debug ("Ignoring ref (%s, %s) due to missing keyring: %s", + refs[j]->collection_id, refs[j]->ref_name, local_error->message); + g_clear_error (&local_error); + continue; + } + + if (g_hash_table_lookup_extended (remote_refs, refs[j], NULL, (gpointer *) &checksum)) + { + g_autoptr(OstreeRemote) remote = NULL; + + /* The requested ref is listed in the refs for this remote. Add + * the remote to the results, and the ref to its + * @supported_ref_to_checksum. */ + g_debug ("Resolved ref (%s, %s) to remote ‘%s’.", + refs[j]->collection_id, refs[j]->ref_name, remote_uri); + resolved_a_ref = TRUE; + + /* Build an #OstreeRemote. Use the escaped URI, since remote->name + * is used in file paths, so needs to not contain special characters. */ + g_autofree gchar *name = uri_and_keyring_to_name (remote_uri, keyring_remote->name); + remote = ostree_remote_new_dynamic (name, keyring_remote->name); + + /* gpg-verify-summary is false since we use the unsigned summary file support. */ + g_key_file_set_string (remote->options, remote->group, "url", remote_uri); + g_key_file_set_boolean (remote->options, remote->group, "gpg-verify", TRUE); + g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", FALSE); + + supported_ref_to_checksum = g_hash_table_lookup (repo_remote_to_refs, remote); + + if (supported_ref_to_checksum == NULL) + { + supported_ref_to_checksum = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + NULL, g_free); + g_hash_table_insert (repo_remote_to_refs, ostree_remote_ref (remote), supported_ref_to_checksum /* transfer */); + } + + g_hash_table_insert (supported_ref_to_checksum, + (gpointer) refs[j], g_strdup (checksum)); + } + } + + if (!resolved_a_ref) + g_debug ("Ignoring remote ‘%s’ due to it not advertising any of the requested refs.", + remote_uri); + } + + /* Aggregate the results. */ + g_hash_table_iter_init (&iter, repo_remote_to_refs); + + while (g_hash_table_iter_next (&iter, (gpointer *) &remote, (gpointer *) &supported_ref_to_checksum)) + g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0)); + + g_ptr_array_sort (results, results_compare_cb); + + g_task_return_pointer (task, g_steal_pointer (&results), (GDestroyNotify) g_ptr_array_unref); +} + +static GPtrArray * +ostree_repo_finder_override_resolve_finish (OstreeRepoFinder *finder, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, finder), NULL); + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +ostree_repo_finder_override_init (OstreeRepoFinderOverride *self) +{ + self->override_uris = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); +} + +static void +ostree_repo_finder_override_finalize (GObject *object) +{ + OstreeRepoFinderOverride *self = OSTREE_REPO_FINDER_OVERRIDE (object); + + g_clear_pointer (&self->override_uris, g_ptr_array_unref); + + G_OBJECT_CLASS (ostree_repo_finder_override_parent_class)->finalize (object); +} + +static void +ostree_repo_finder_override_class_init (OstreeRepoFinderOverrideClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = ostree_repo_finder_override_finalize; +} + +static void +ostree_repo_finder_override_iface_init (OstreeRepoFinderInterface *iface) +{ + iface->resolve_async = ostree_repo_finder_override_resolve_async; + iface->resolve_finish = ostree_repo_finder_override_resolve_finish; +} + +/** + * ostree_repo_finder_override_new: + * + * Create a new #OstreeRepoFinderOverride. + * + * Returns: (transfer full): a new #OstreeRepoFinderOverride + * Since: 2018.6 + */ +OstreeRepoFinderOverride * +ostree_repo_finder_override_new (void) +{ + return g_object_new (OSTREE_TYPE_REPO_FINDER_OVERRIDE, NULL); +} + +/** + * ostree_repo_finder_override_add_uri: + * @uri: URI to add to the repo finder + * + * Add the given @uri to the set of URIs which the repo finder will search for + * matching refs when ostree_repo_finder_resolve_async() is called on it. + * + * Since: 2018.6 + */ +void +ostree_repo_finder_override_add_uri (OstreeRepoFinderOverride *self, + const gchar *uri) +{ + g_return_if_fail (OSTREE_IS_REPO_FINDER_OVERRIDE (self)); + g_return_if_fail (uri != NULL); + + g_ptr_array_add (self->override_uris, g_strdup (uri)); +} diff --git a/src/libostree/ostree-repo-finder-override.h b/src/libostree/ostree-repo-finder-override.h new file mode 100644 index 0000000..8bce35e --- /dev/null +++ b/src/libostree/ostree-repo-finder-override.h @@ -0,0 +1,60 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "ostree-repo-finder.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_REPO_FINDER_OVERRIDE (ostree_repo_finder_override_get_type ()) + +/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44): +_OSTREE_PUBLIC +G_DECLARE_FINAL_TYPE (OstreeRepoFinderOverride, ostree_repo_finder_override, OSTREE, REPO_FINDER_OVERRIDE, GObject) */ + +_OSTREE_PUBLIC +GType ostree_repo_finder_override_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeRepoFinderOverride OstreeRepoFinderOverride; +typedef struct { GObjectClass parent_class; } OstreeRepoFinderOverrideClass; + +static inline OstreeRepoFinderOverride *OSTREE_REPO_FINDER_OVERRIDE (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_repo_finder_override_get_type (), OstreeRepoFinderOverride); } +static inline gboolean OSTREE_IS_REPO_FINDER_OVERRIDE (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_repo_finder_override_get_type ()); } +G_GNUC_END_IGNORE_DEPRECATIONS + +_OSTREE_PUBLIC +OstreeRepoFinderOverride *ostree_repo_finder_override_new (void); + +_OSTREE_PUBLIC +void ostree_repo_finder_override_add_uri (OstreeRepoFinderOverride *self, + const gchar *uri); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-finder.c b/src/libostree/ostree-repo-finder.c new file mode 100644 index 0000000..ed44ddc --- /dev/null +++ b/src/libostree/ostree-repo-finder.c @@ -0,0 +1,586 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-core.h" +#include "ostree-remote-private.h" +#include "ostree-repo-finder.h" +#include "ostree-repo.h" + +static void ostree_repo_finder_default_init (OstreeRepoFinderInterface *iface); + +G_DEFINE_INTERFACE (OstreeRepoFinder, ostree_repo_finder, G_TYPE_OBJECT) + +static void +ostree_repo_finder_default_init (OstreeRepoFinderInterface *iface) +{ + /* Nothing to see here. */ +} + +/* Validate the given struct contains a valid collection ID and ref name, and that + * the collection ID is non-%NULL. */ +static gboolean +is_valid_collection_ref (const OstreeCollectionRef *ref) +{ + return (ref != NULL && + ostree_validate_rev (ref->ref_name, NULL) && + ostree_validate_collection_id (ref->collection_id, NULL)); +} + +/* Validate @refs is non-%NULL, non-empty, and contains only valid collection + * and ref names. */ +static gboolean +is_valid_collection_ref_array (const OstreeCollectionRef * const *refs) +{ + gsize i; + + if (refs == NULL || *refs == NULL) + return FALSE; + + for (i = 0; refs[i] != NULL; i++) + { + if (!is_valid_collection_ref (refs[i])) + return FALSE; + } + + return TRUE; +} + +/* Validate @ref_to_checksum is non-%NULL, non-empty, and contains only valid + * OstreeCollectionRefs as keys and only valid commit checksums as values. */ +static gboolean +is_valid_collection_ref_map (GHashTable *ref_to_checksum) +{ + GHashTableIter iter; + const OstreeCollectionRef *ref; + const gchar *checksum; + + if (ref_to_checksum == NULL || g_hash_table_size (ref_to_checksum) == 0) + return FALSE; + + g_hash_table_iter_init (&iter, ref_to_checksum); + + while (g_hash_table_iter_next (&iter, (gpointer *) &ref, (gpointer *) &checksum)) + { + g_assert (ref != NULL); + g_assert (checksum != NULL); + + if (!is_valid_collection_ref (ref)) + return FALSE; + if (!ostree_validate_checksum_string (checksum, NULL)) + return FALSE; + } + + return TRUE; +} + +static void resolve_cb (GObject *obj, + GAsyncResult *result, + gpointer user_data); + +/** + * ostree_repo_finder_resolve_async: + * @self: an #OstreeRepoFinder + * @refs: (array zero-terminated=1): non-empty array of collection–ref pairs to find remotes for + * @parent_repo: (transfer none): the local repository which the refs are being resolved for, + * which provides configuration information and GPG keys + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: asynchronous completion callback + * @user_data: data to pass to @callback + * + * Find reachable remote URIs which claim to provide any of the given @refs. The + * specific method for finding the remotes depends on the #OstreeRepoFinder + * implementation. + * + * Any remote which is found and which claims to support any of the given @refs + * will be returned in the results. It is possible that a remote claims to + * support a given ref, but turns out not to — it is not possible to verify this + * until ostree_repo_pull_from_remotes_async() is called. + * + * The returned results will be sorted with the most useful first — this is + * typically the remote which claims to provide the most @refs, at the lowest + * latency. + * + * Each result contains a mapping of @refs to the checksums of the commits + * which the result provides. If the result provides the latest commit for a ref + * across all of the results, the checksum will be set. Otherwise, if the + * result provides an outdated commit, or doesn’t provide a given ref at all, + * the checksum will not be set. Results which provide none of the requested + * @refs may be listed with an empty refs map. + * + * Pass the results to ostree_repo_pull_from_remotes_async() to pull the given + * @refs from those remotes. + * + * Since: 2018.6 + */ +void +ostree_repo_finder_resolve_async (OstreeRepoFinder *self, + const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + OstreeRepoFinder *finders[2] = { NULL, }; + + g_return_if_fail (OSTREE_IS_REPO_FINDER (self)); + g_return_if_fail (is_valid_collection_ref_array (refs)); + g_return_if_fail (OSTREE_IS_REPO (parent_repo)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, ostree_repo_finder_resolve_async); + + finders[0] = self; + + ostree_repo_finder_resolve_all_async (finders, refs, parent_repo, cancellable, + resolve_cb, g_steal_pointer (&task)); +} + +static void +resolve_cb (GObject *obj, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + g_autoptr(GPtrArray) results = NULL; + g_autoptr(GError) local_error = NULL; + + task = G_TASK (user_data); + + results = ostree_repo_finder_resolve_all_finish (result, &local_error); + + g_assert ((local_error == NULL) != (results == NULL)); + + if (local_error != NULL) + g_task_return_error (task, g_steal_pointer (&local_error)); + else + g_task_return_pointer (task, g_steal_pointer (&results), (GDestroyNotify) g_ptr_array_unref); +} + +/** + * ostree_repo_finder_resolve_finish: + * @self: an #OstreeRepoFinder + * @result: #GAsyncResult from the callback + * @error: return location for a #GError + * + * Get the results from a ostree_repo_finder_resolve_async() operation. + * + * Returns: (transfer full) (element-type OstreeRepoFinderResult): array of zero + * or more results + * Since: 2018.6 + */ +GPtrArray * +ostree_repo_finder_resolve_finish (OstreeRepoFinder *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_REPO_FINDER (self), NULL); + g_return_val_if_fail (g_task_is_valid (result, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} + +static gint +sort_results_cb (gconstpointer a, + gconstpointer b) +{ + const OstreeRepoFinderResult *result_a = *((const OstreeRepoFinderResult **) a); + const OstreeRepoFinderResult *result_b = *((const OstreeRepoFinderResult **) b); + + return ostree_repo_finder_result_compare (result_a, result_b); +} + +typedef struct +{ + gsize n_finders_pending; + GPtrArray *results; +} ResolveAllData; + +static void +resolve_all_data_free (ResolveAllData *data) +{ + g_assert (data->n_finders_pending == 0); + g_clear_pointer (&data->results, g_ptr_array_unref); + g_free (data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (ResolveAllData, resolve_all_data_free) + +static void resolve_all_cb (GObject *obj, + GAsyncResult *result, + gpointer user_data); +static void resolve_all_finished_one (GTask *task); + +/** + * ostree_repo_finder_resolve_all_async: + * @finders: (array zero-terminated=1): non-empty array of #OstreeRepoFinders + * @refs: (array zero-terminated=1): non-empty array of collection–ref pairs to find remotes for + * @parent_repo: (transfer none): the local repository which the refs are being resolved for, + * which provides configuration information and GPG keys + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: asynchronous completion callback + * @user_data: data to pass to @callback + * + * A version of ostree_repo_finder_resolve_async() which queries one or more + * @finders in parallel and combines the results. + * + * Since: 2018.6 + */ +void +ostree_repo_finder_resolve_all_async (OstreeRepoFinder * const *finders, + const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + g_autoptr(ResolveAllData) data = NULL; + gsize i; + g_autoptr(GString) refs_str = NULL; + g_autoptr(GString) finders_str = NULL; + + g_return_if_fail (finders != NULL && finders[0] != NULL); + g_return_if_fail (is_valid_collection_ref_array (refs)); + g_return_if_fail (OSTREE_IS_REPO (parent_repo)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + refs_str = g_string_new (""); + for (i = 0; refs[i] != NULL; i++) + { + if (i != 0) + g_string_append (refs_str, ", "); + g_string_append_printf (refs_str, "(%s, %s)", + refs[i]->collection_id, refs[i]->ref_name); + } + + finders_str = g_string_new (""); + for (i = 0; finders[i] != NULL; i++) + { + if (i != 0) + g_string_append (finders_str, ", "); + g_string_append (finders_str, g_type_name (G_TYPE_FROM_INSTANCE (finders[i]))); + } + + g_debug ("%s: Resolving refs [%s] with finders [%s]", G_STRFUNC, + refs_str->str, finders_str->str); + + task = g_task_new (NULL, cancellable, callback, user_data); + g_task_set_source_tag (task, ostree_repo_finder_resolve_all_async); + + data = g_new0 (ResolveAllData, 1); + data->n_finders_pending = 1; /* while setting up the loop */ + data->results = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_repo_finder_result_free); + g_task_set_task_data (task, data, (GDestroyNotify) resolve_all_data_free); + + /* Start all the asynchronous queries in parallel. */ + for (i = 0; finders[i] != NULL; i++) + { + OstreeRepoFinder *finder = OSTREE_REPO_FINDER (finders[i]); + OstreeRepoFinderInterface *iface; + + iface = OSTREE_REPO_FINDER_GET_IFACE (finder); + g_assert (iface->resolve_async != NULL); + iface->resolve_async (finder, refs, parent_repo, cancellable, resolve_all_cb, g_object_ref (task)); + data->n_finders_pending++; + } + + resolve_all_finished_one (task); + data = NULL; /* passed to the GTask above */ +} + +/* Modifies both arrays in place. */ +static void +array_concatenate_steal (GPtrArray *array, + GPtrArray *to_concatenate) /* (transfer full) */ +{ + g_autoptr(GPtrArray) array_to_concatenate = to_concatenate; + gsize i; + + for (i = 0; i < array_to_concatenate->len; i++) + { + /* Sanity check that the arrays do not contain any %NULL elements + * (particularly NULL terminators). */ + g_assert (g_ptr_array_index (array_to_concatenate, i) != NULL); + g_ptr_array_add (array, g_steal_pointer (&g_ptr_array_index (array_to_concatenate, i))); + } + + g_ptr_array_set_free_func (array_to_concatenate, NULL); + g_ptr_array_set_size (array_to_concatenate, 0); +} + +static void +resolve_all_cb (GObject *obj, + GAsyncResult *result, + gpointer user_data) +{ + OstreeRepoFinder *finder; + OstreeRepoFinderInterface *iface; + g_autoptr(GTask) task = NULL; + g_autoptr(GPtrArray) results = NULL; + g_autoptr(GError) local_error = NULL; + ResolveAllData *data; + + finder = OSTREE_REPO_FINDER (obj); + iface = OSTREE_REPO_FINDER_GET_IFACE (finder); + task = G_TASK (user_data); + data = g_task_get_task_data (task); + results = iface->resolve_finish (finder, result, &local_error); + + g_assert ((local_error == NULL) != (results == NULL)); + + if (local_error != NULL) + g_debug ("Error resolving refs to repository URI using %s: %s", + g_type_name (G_TYPE_FROM_INSTANCE (finder)), local_error->message); + else + array_concatenate_steal (data->results, g_steal_pointer (&results)); + + resolve_all_finished_one (task); +} + +static void +resolve_all_finished_one (GTask *task) +{ + ResolveAllData *data; + + data = g_task_get_task_data (task); + + data->n_finders_pending--; + + if (data->n_finders_pending == 0) + { + gsize i; + g_autoptr(GString) results_str = NULL; + + g_ptr_array_sort (data->results, sort_results_cb); + + results_str = g_string_new (""); + for (i = 0; i < data->results->len; i++) + { + const OstreeRepoFinderResult *result = g_ptr_array_index (data->results, i); + + if (i != 0) + g_string_append (results_str, ", "); + g_string_append (results_str, ostree_remote_get_name (result->remote)); + } + if (i == 0) + g_string_append (results_str, "(none)"); + + g_debug ("%s: Finished, results: %s", G_STRFUNC, results_str->str); + + g_task_return_pointer (task, g_steal_pointer (&data->results), (GDestroyNotify) g_ptr_array_unref); + } +} + +/** + * ostree_repo_finder_resolve_all_finish: + * @result: #GAsyncResult from the callback + * @error: return location for a #GError + * + * Get the results from a ostree_repo_finder_resolve_all_async() operation. + * + * Returns: (transfer full) (element-type OstreeRepoFinderResult): array of zero + * or more results + * Since: 2018.6 + */ +GPtrArray * +ostree_repo_finder_resolve_all_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} + +G_DEFINE_BOXED_TYPE (OstreeRepoFinderResult, ostree_repo_finder_result, + ostree_repo_finder_result_dup, ostree_repo_finder_result_free) + +/** + * ostree_repo_finder_result_new: + * @remote: (transfer none): an #OstreeRemote containing the transport details + * for the result + * @finder: (transfer none): the #OstreeRepoFinder instance which produced the + * result + * @priority: static priority of the result, where higher numbers indicate lower + * priority + * @ref_to_checksum: (element-type OstreeCollectionRef utf8) (transfer none): + * map of collection–ref pairs to checksums provided by this result + * @ref_to_timestamp: (element-type OstreeCollectionRef guint64) (nullable) + * (transfer none): map of collection–ref pairs to timestamps provided by this + * result + * @summary_last_modified: Unix timestamp (seconds since the epoch, UTC) when + * the summary file for the result was last modified, or `0` if this is unknown + * + * Create a new #OstreeRepoFinderResult instance. The semantics for the arguments + * are as described in the #OstreeRepoFinderResult documentation. + * + * Returns: (transfer full): a new #OstreeRepoFinderResult + * Since: 2018.6 + */ +OstreeRepoFinderResult * +ostree_repo_finder_result_new (OstreeRemote *remote, + OstreeRepoFinder *finder, + gint priority, + GHashTable *ref_to_checksum, + GHashTable *ref_to_timestamp, + guint64 summary_last_modified) +{ + g_autoptr(OstreeRepoFinderResult) result = NULL; + + g_return_val_if_fail (remote != NULL, NULL); + g_return_val_if_fail (OSTREE_IS_REPO_FINDER (finder), NULL); + g_return_val_if_fail (is_valid_collection_ref_map (ref_to_checksum), NULL); + + result = g_new0 (OstreeRepoFinderResult, 1); + result->remote = ostree_remote_ref (remote); + result->finder = g_object_ref (finder); + result->priority = priority; + result->ref_to_checksum = g_hash_table_ref (ref_to_checksum); + result->ref_to_timestamp = ref_to_timestamp != NULL ? g_hash_table_ref (ref_to_timestamp) : NULL; + result->summary_last_modified = summary_last_modified; + + return g_steal_pointer (&result); +} + +/** + * ostree_repo_finder_result_dup: + * @result: (transfer none): an #OstreeRepoFinderResult to copy + * + * Copy an #OstreeRepoFinderResult. + * + * Returns: (transfer full): a newly allocated copy of @result + * Since: 2018.6 + */ +OstreeRepoFinderResult * +ostree_repo_finder_result_dup (OstreeRepoFinderResult *result) +{ + g_return_val_if_fail (result != NULL, NULL); + + return ostree_repo_finder_result_new (result->remote, result->finder, + result->priority, result->ref_to_checksum, + result->ref_to_timestamp, result->summary_last_modified); +} + +/** + * ostree_repo_finder_result_compare: + * @a: an #OstreeRepoFinderResult + * @b: an #OstreeRepoFinderResult + * + * Compare two #OstreeRepoFinderResult instances to work out which one is better + * to pull from, and hence needs to be ordered before the other. + * + * Returns: <0 if @a is ordered before @b, 0 if they are ordered equally, + * >0 if @b is ordered before @a + * Since: 2018.6 + */ +gint +ostree_repo_finder_result_compare (const OstreeRepoFinderResult *a, + const OstreeRepoFinderResult *b) +{ + guint a_n_refs, b_n_refs; + + g_return_val_if_fail (a != NULL, 0); + g_return_val_if_fail (b != NULL, 0); + + /* FIXME: Check if this is really the ordering we want. For example, we + * probably don’t want a result with 0 refs to be ordered before one with >0 + * refs, just because its priority is higher. */ + if (a->priority != b->priority) + return a->priority - b->priority; + + if (a->summary_last_modified != 0 && b->summary_last_modified != 0 && + a->summary_last_modified != b->summary_last_modified) + return a->summary_last_modified - b->summary_last_modified; + + gpointer value; + GHashTableIter iter; + a_n_refs = b_n_refs = 0; + + g_hash_table_iter_init (&iter, a->ref_to_checksum); + while (g_hash_table_iter_next (&iter, NULL, &value)) + if (value != NULL) + a_n_refs++; + + g_hash_table_iter_init (&iter, b->ref_to_checksum); + while (g_hash_table_iter_next (&iter, NULL, &value)) + if (value != NULL) + b_n_refs++; + + if (a_n_refs != b_n_refs) + return (gint) a_n_refs - (gint) b_n_refs; + + return g_strcmp0 (a->remote->name, b->remote->name); +} + +/** + * ostree_repo_finder_result_free: + * @result: (transfer full): an #OstreeRepoFinderResult + * + * Free the given @result. + * + * Since: 2018.6 + */ +void +ostree_repo_finder_result_free (OstreeRepoFinderResult *result) +{ + g_return_if_fail (result != NULL); + + /* This may be NULL iff the result is freed half-way through find_remotes_cb() + * in ostree-repo-pull.c, and at no other time. */ + g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref); + g_clear_pointer (&result->ref_to_timestamp, g_hash_table_unref); + g_object_unref (result->finder); + ostree_remote_unref (result->remote); + g_free (result); +} + +/** + * ostree_repo_finder_result_freev: + * @results: (array zero-terminated=1) (transfer full): an #OstreeRepoFinderResult + * + * Free the given @results array, freeing each element and the container. + * + * Since: 2018.6 + */ +void +ostree_repo_finder_result_freev (OstreeRepoFinderResult **results) +{ + gsize i; + + for (i = 0; results[i] != NULL; i++) + ostree_repo_finder_result_free (results[i]); + + g_free (results); +} diff --git a/src/libostree/ostree-repo-finder.h b/src/libostree/ostree-repo-finder.h new file mode 100644 index 0000000..f9c2619 --- /dev/null +++ b/src/libostree/ostree-repo-finder.h @@ -0,0 +1,188 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "ostree-ref.h" +#include "ostree-remote.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_REPO_FINDER (ostree_repo_finder_get_type ()) + +/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44): +_OSTREE_PUBLIC +G_DECLARE_INTERFACE (OstreeRepoFinder, ostree_repo_finder, OSTREE, REPO_FINDER, GObject) */ + +_OSTREE_PUBLIC +GType ostree_repo_finder_get_type (void); +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeRepoFinder OstreeRepoFinder; +typedef struct _OstreeRepoFinderInterface OstreeRepoFinderInterface; + +static inline OstreeRepoFinder *OSTREE_REPO_FINDER (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_repo_finder_get_type (), OstreeRepoFinder); } +static inline gboolean OSTREE_IS_REPO_FINDER (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_repo_finder_get_type ()); } +static inline OstreeRepoFinderInterface *OSTREE_REPO_FINDER_GET_IFACE (gpointer ptr) { return G_TYPE_INSTANCE_GET_INTERFACE (ptr, ostree_repo_finder_get_type (), OstreeRepoFinderInterface); } +G_GNUC_END_IGNORE_DEPRECATIONS + +struct _OstreeRepoFinderInterface +{ + GTypeInterface g_iface; + + void (*resolve_async) (OstreeRepoFinder *self, + const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + GPtrArray *(*resolve_finish) (OstreeRepoFinder *self, + GAsyncResult *result, + GError **error); +}; + +_OSTREE_PUBLIC +void ostree_repo_finder_resolve_async (OstreeRepoFinder *self, + const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +_OSTREE_PUBLIC +GPtrArray *ostree_repo_finder_resolve_finish (OstreeRepoFinder *self, + GAsyncResult *result, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_finder_resolve_all_async (OstreeRepoFinder * const *finders, + const OstreeCollectionRef * const *refs, + OstreeRepo *parent_repo, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +_OSTREE_PUBLIC +GPtrArray *ostree_repo_finder_resolve_all_finish (GAsyncResult *result, + GError **error); + +/** + * OstreeRepoFinderResult: + * @remote: #OstreeRemote which contains the transport details for the result, + * such as its URI and GPG key + * @finder: the #OstreeRepoFinder instance which produced this result + * @priority: static priority of the result, where higher numbers indicate lower + * priority + * @ref_to_checksum: (element-type OstreeCollectionRef utf8): map of collection–ref + * pairs to checksums provided by this remote; values may be %NULL to + * indicate this remote doesn’t provide that ref + * @ref_to_timestamp: (element-type OstreeCollectionRef guint64) (nullable): map of + * collection–ref pairs to timestamps; values may be 0 for various reasons + * @summary_last_modified: Unix timestamp (seconds since the epoch, UTC) when + * the summary file on the remote was last modified, or `0` if unknown + * + * #OstreeRepoFinderResult gives a single result from an + * ostree_repo_finder_resolve_async() or ostree_repo_finder_resolve_all_async() + * operation. This represents a single remote which provides none, some or all + * of the refs being resolved. The structure includes various bits of metadata + * which allow ostree_repo_pull_from_remotes_async() (for example) to prioritise + * how to pull the refs. + * + * An #OstreeRepoFinderResult is immutable after construction. + * + * The @priority is used as one input of many to ordering functions like + * ostree_repo_finder_result_compare(). + * + * @ref_to_checksum indicates which refs (out of the ones queried for as inputs + * to ostree_repo_finder_resolve_async()) are provided by this remote. The refs + * are present as keys (of type #OstreeCollectionRef), and the corresponding values + * are the checksums of the commits the remote currently has for those refs. (These + * might not be the latest commits available out of all results.) A + * checksum may be %NULL if the remote does not advertise the corresponding ref. + * After ostree_repo_finder_resolve_async() has been called, the commit metadata + * should be available locally, so the details for each checksum can be looked + * up using ostree_repo_load_commit(). + * + * @ref_to_timestamp provides timestamps for the set of refs in + * @ref_to_checksum. The refs are keys (of type #OstreeCollectionRef) and the + * values are guint64 pointers with the timestamp associated with the checksum + * provided in @ref_to_checksum. @ref_to_timestamp can be %NULL, and when it's + * not, the timestamps are zero when any of the following conditions are met: + * (1) the override-commit-ids option was used on + * ostree_repo_find_remotes_async (2) there was an error in trying to get the + * commit metadata (3) the checksum for this ref is %NULL in @ref_to_checksum. + * + * Since: 2018.6 + */ +typedef struct +{ + OstreeRemote *remote; + OstreeRepoFinder *finder; + gint priority; + GHashTable *ref_to_checksum; + guint64 summary_last_modified; + GHashTable *ref_to_timestamp; + + /*< private >*/ + gpointer padding[3]; +} OstreeRepoFinderResult; + +_OSTREE_PUBLIC +GType ostree_repo_finder_result_get_type (void); + +_OSTREE_PUBLIC +OstreeRepoFinderResult *ostree_repo_finder_result_new (OstreeRemote *remote, + OstreeRepoFinder *finder, + gint priority, + GHashTable *ref_to_checksum, + GHashTable *ref_to_timestamp, + guint64 summary_last_modified); +_OSTREE_PUBLIC +OstreeRepoFinderResult *ostree_repo_finder_result_dup (OstreeRepoFinderResult *result); +_OSTREE_PUBLIC +gint ostree_repo_finder_result_compare (const OstreeRepoFinderResult *a, + const OstreeRepoFinderResult *b); +_OSTREE_PUBLIC +void ostree_repo_finder_result_free (OstreeRepoFinderResult *result); + +/** + * OstreeRepoFinderResultv: + * + * A %NULL-terminated array of #OstreeRepoFinderResult instances, designed to + * be used with g_auto(): + * + * |[ + * g_auto(OstreeRepoFinderResultv) results = NULL; + * ]| + * + * Since: 2018.6 + */ +typedef OstreeRepoFinderResult** OstreeRepoFinderResultv; + +_OSTREE_PUBLIC +void ostree_repo_finder_result_freev (OstreeRepoFinderResult **results); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-libarchive.c b/src/libostree/ostree-repo-libarchive.c new file mode 100644 index 0000000..d55459f --- /dev/null +++ b/src/libostree/ostree-repo-libarchive.c @@ -0,0 +1,1259 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "otutil.h" +#include "ostree.h" +#include "ostree-core-private.h" +#include "ostree-repo-private.h" + +#ifdef HAVE_LIBARCHIVE +#include +#include +#include "ostree-libarchive-input-stream.h" +#endif + +#include "otutil.h" + +#ifdef HAVE_LIBARCHIVE + +#define DEFAULT_DIRMODE (0755 | S_IFDIR) + +static void +propagate_libarchive_error (GError **error, + struct archive *a) +{ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", archive_error_string (a)); +} + +static const char * +path_relative (const char *src, + GError **error) +{ + /* One issue here is that some archives almost record the pathname as just a + * string and don't need to actually encode parent/child relationships in the + * archive. For us however, this will be important. So we do our best to deal + * with non-conventional paths. We also validate the path at the end to make + * sure there are no illegal components. Also important, we relativize the + * path. */ + + /* relativize first (and make /../../ --> /) */ + while (src[0] == '/') + { + src += 1; + if (src[0] == '.' && src[1] == '.' && src[2] == '/') + src += 2; /* keep trailing / so we continue */ + } + + /* now let's skip . and empty components */ + while (TRUE) + { + if (src[0] == '.' && src[1] == '/') + src += 2; + else if (src[0] == '/') + src += 1; + else + break; + } + + /* assume a single '.' means the root dir itself, which we handle as the empty + * string in our code */ + if (src[0] == '.' && src[1] == '\0') + src += 1; + + /* make sure that the final path is valid (no . or ..) */ + if (!ot_util_path_split_validate (src, NULL, error)) + { + g_prefix_error (error, "While making relative path \"%s\":", src); + return NULL; + } + + return src; +} + +static char * +path_relative_ostree (const char *path, + GError **error) +{ + path = path_relative (path, error); + if (path == NULL) + return NULL; + if (g_str_has_prefix (path, "etc/")) + return g_strconcat ("usr/", path, NULL); + else if (strcmp (path, "etc") == 0) + return g_strdup ("usr/etc"); + return g_strdup (path); +} + +static void +append_path_component (char **path_builder, + const char *component) +{ + g_autofree char *s = g_steal_pointer (path_builder); + *path_builder = g_build_filename (s ?: "/", component, NULL); +} + +/* inplace trailing slash squashing */ +static void +squash_trailing_slashes (char *path) +{ + char *endp = path + strlen (path) - 1; + for (; endp > path && *endp == '/'; endp--) + *endp = '\0'; +} + +/* Like archive_entry_stat(), but since some archives only store the permission + * mode bits in hardlink entries, so let's just make it into a regular file. + * Yes, this hack will work even if it's a hardlink to a symlink. + */ +static void +read_archive_entry_stat (struct archive_entry *entry, + struct stat *stbuf) +{ + const struct stat *st = archive_entry_stat (entry); + + *stbuf = *st; + if (archive_entry_hardlink (entry)) + stbuf->st_mode |= S_IFREG; +} + +/* Create a GFileInfo from archive_entry_stat() */ +static GFileInfo * +file_info_from_archive_entry (struct archive_entry *entry) +{ + struct stat stbuf; + read_archive_entry_stat (entry, &stbuf); + + g_autoptr(GFileInfo) info = _ostree_stbuf_to_gfileinfo (&stbuf); + if (S_ISLNK (stbuf.st_mode)) + g_file_info_set_attribute_byte_string (info, "standard::symlink-target", + archive_entry_symlink (entry)); + + return g_steal_pointer (&info); +} + +static gboolean +builder_add_label (GVariantBuilder *builder, + OstreeSePolicy *sepolicy, + const char *path, + mode_t mode, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *label = NULL; + + if (!sepolicy) + return TRUE; + + if (!ostree_sepolicy_get_label (sepolicy, path, mode, &label, + cancellable, error)) + return FALSE; + + if (label) + g_variant_builder_add (builder, "(@ay@ay)", + g_variant_new_bytestring ("security.selinux"), + g_variant_new_bytestring (label)); + return TRUE; +} + + +/* Like ostree_mutable_tree_ensure_dir(), but also creates and sets dirmeta if + * the dir has to be created. */ +static gboolean +mtree_ensure_dir_with_meta (OstreeRepo *repo, + OstreeMutableTree *parent, + const char *name, + GFileInfo *file_info, + GVariant *xattrs, + gboolean error_if_exist, /* XXX: remove if not needed */ + OstreeMutableTree **out_dir, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeMutableTree) dir = NULL; + g_autofree guchar *csum_raw = NULL; + g_autofree char *csum = NULL; + + if (name[0] == '\0') /* root? */ + dir = g_object_ref (parent); + else if (ostree_mutable_tree_lookup (parent, name, NULL, &dir, error)) + { + if (error_if_exist) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Directory \"%s\" already exists", name); + return FALSE; + } + } + + if (dir == NULL) + { + if (!g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return FALSE; + + g_clear_error (error); + + if (!ostree_mutable_tree_ensure_dir (parent, name, &dir, error)) + return FALSE; + } + + if (!_ostree_repo_write_directory_meta (repo, file_info, xattrs, + &csum_raw, cancellable, error)) + return FALSE; + + csum = ostree_checksum_from_bytes (csum_raw); + + ostree_mutable_tree_set_metadata_checksum (dir, csum); + + if (out_dir) + *out_dir = g_steal_pointer (&dir); + + return TRUE; +} + +typedef struct { + OstreeRepo *repo; + OstreeRepoImportArchiveOptions *opts; + OstreeMutableTree *root; + struct archive *archive; + struct archive_entry *entry; + GHashTable *deferred_hardlinks; + OstreeRepoCommitModifier *modifier; +} OstreeRepoArchiveImportContext; + +typedef struct { + OstreeMutableTree *parent; + char *path; + guint64 size; +} DeferredHardlink; + +static inline char* +aic_get_final_path (OstreeRepoArchiveImportContext *ctx, + const char *path, + GError **error) +{ + if (ctx->opts->translate_pathname) + { + struct stat stbuf; + path = path_relative (path, error); + read_archive_entry_stat (ctx->entry, &stbuf); + char *ret = ctx->opts->translate_pathname (ctx->repo, &stbuf, path, + ctx->opts->translate_pathname_user_data); + if (ret) + return ret; + /* Fall through */ + } + else if (ctx->opts->use_ostree_convention) + return path_relative_ostree (path, error); + return g_strdup (path_relative (path, error)); +} + +static inline char* +aic_get_final_entry_pathname (OstreeRepoArchiveImportContext *ctx, + GError **error) +{ + const char *pathname = archive_entry_pathname (ctx->entry); + g_autofree char *final = aic_get_final_path (ctx, pathname, error); + if (final == NULL) + return NULL; + + /* get rid of trailing slashes some archives put on dirs */ + squash_trailing_slashes (final); + return g_steal_pointer (&final); +} + +static inline char* +aic_get_final_entry_hardlink (OstreeRepoArchiveImportContext *ctx) +{ + GError *local_error = NULL; + const char *hardlink = archive_entry_hardlink (ctx->entry); + g_autofree char *final = NULL; + + if (hardlink != NULL) + { + final = aic_get_final_path (ctx, hardlink, &local_error); + + /* hardlinks always point to a preceding entry, so if there were an error + * it would have failed then */ + g_assert_no_error (local_error); + } + + return g_steal_pointer (&final); +} + +static OstreeRepoCommitFilterResult +aic_apply_modifier_filter (OstreeRepoArchiveImportContext *ctx, + const char *relpath, + GFileInfo **out_file_info) +{ + g_autoptr(GFileInfo) file_info = NULL; + g_autofree char *abspath = NULL; + const char *cb_path = NULL; + + if (ctx->opts->callback_with_entry_pathname) + cb_path = archive_entry_pathname (ctx->entry); + else + { + /* the user expects an abspath (where the dir to commit represents /) */ + abspath = g_build_filename ("/", relpath, NULL); + cb_path = abspath; + } + + file_info = file_info_from_archive_entry (ctx->entry); + + return _ostree_repo_commit_modifier_apply (ctx->repo, ctx->modifier, cb_path, + file_info, out_file_info); +} + +static gboolean +aic_ensure_parent_dir_with_file_info (OstreeRepoArchiveImportContext *ctx, + OstreeMutableTree *parent, + const char *fullpath, + GFileInfo *file_info, + OstreeMutableTree **out_dir, + GCancellable *cancellable, + GError **error) +{ + const char *name = glnx_basename (fullpath); + g_auto(GVariantBuilder) xattrs_builder; + g_autoptr(GVariant) xattrs = NULL; + + /* is this the root directory itself? transform into empty string */ + if (name[0] == '/' && name[1] == '\0') + name++; + + g_variant_builder_init (&xattrs_builder, (GVariantType*)"a(ayay)"); + + if (ctx->modifier && ctx->modifier->sepolicy) + if (!builder_add_label (&xattrs_builder, ctx->modifier->sepolicy, fullpath, + DEFAULT_DIRMODE, cancellable, error)) + return FALSE; + + xattrs = g_variant_ref_sink (g_variant_builder_end (&xattrs_builder)); + return mtree_ensure_dir_with_meta (ctx->repo, parent, name, file_info, + xattrs, + FALSE /* error_if_exist */, out_dir, + cancellable, error); +} + +static gboolean +aic_ensure_parent_dir (OstreeRepoArchiveImportContext *ctx, + OstreeMutableTree *parent, + const char *fullpath, + OstreeMutableTree **out_dir, + GCancellable *cancellable, + GError **error) +{ + /* Who should own the parent dir? Since it's not in the archive, it's up to + * us. Here, we use the heuristic of simply creating it as the same user as + * the owner of the archive entry for which we're creating the dir. This is OK + * since any nontrivial dir perms should have explicit archive entries. */ + + guint32 uid = archive_entry_uid (ctx->entry); + guint32 gid = archive_entry_gid (ctx->entry); + glnx_unref_object GFileInfo *file_info = g_file_info_new (); + + g_file_info_set_attribute_uint32 (file_info, "unix::uid", uid); + g_file_info_set_attribute_uint32 (file_info, "unix::gid", gid); + g_file_info_set_attribute_uint32 (file_info, "unix::mode", DEFAULT_DIRMODE); + + return aic_ensure_parent_dir_with_file_info (ctx, parent, fullpath, file_info, + out_dir, cancellable, error); +} + +static gboolean +aic_create_parent_dirs (OstreeRepoArchiveImportContext *ctx, + GPtrArray *components, + OstreeMutableTree **out_subdir, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *fullpath = NULL; + g_autoptr(OstreeMutableTree) dir = NULL; + + /* start with the root itself */ + if (!aic_ensure_parent_dir (ctx, ctx->root, "/", &dir, cancellable, error)) + return FALSE; + + for (guint i = 0; i < components->len-1; i++) + { + glnx_unref_object OstreeMutableTree *subdir = NULL; + append_path_component (&fullpath, components->pdata[i]); + + if (!aic_ensure_parent_dir (ctx, dir, fullpath, &subdir, + cancellable, error)) + return FALSE; + + g_set_object (&dir, subdir); + } + + *out_subdir = g_steal_pointer (&dir); + return TRUE; +} + +static gboolean +aic_get_parent_dir (OstreeRepoArchiveImportContext *ctx, + const char *path, + OstreeMutableTree **out_dir, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GPtrArray) components = NULL; + if (!ot_util_path_split_validate (path, &components, error)) + return FALSE; + + if (components->len == 0) /* root dir? */ + { + *out_dir = g_object_ref (ctx->root); + return TRUE; + } + + if (ostree_mutable_tree_walk (ctx->root, components, 0, out_dir, error)) + return TRUE; /* already exists, nice! */ + + if (!g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return FALSE; /* some other error occurred */ + + if (ctx->opts->autocreate_parents) + { + g_clear_error (error); + return aic_create_parent_dirs (ctx, components, out_dir, + cancellable, error); + } + + return FALSE; +} + +static gboolean +aic_get_xattrs (OstreeRepoArchiveImportContext *ctx, + const char *path, + GFileInfo *file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *abspath = g_build_filename ("/", path, NULL); + g_autoptr(GVariant) xattrs = NULL; + const char *cb_path = abspath; + + if (ctx->opts->callback_with_entry_pathname) + cb_path = archive_entry_pathname (ctx->entry); + + if (ctx->modifier && ctx->modifier->xattr_callback) + xattrs = ctx->modifier->xattr_callback (ctx->repo, cb_path, file_info, + ctx->modifier->xattr_user_data); + + if (ctx->modifier && ctx->modifier->sepolicy) + { + mode_t mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + g_autoptr(GVariantBuilder) builder = + ot_util_variant_builder_from_variant (xattrs, G_VARIANT_TYPE + ("a(ayay)")); + + if (!builder_add_label (builder, ctx->modifier->sepolicy, abspath, mode, + cancellable, error)) + return FALSE; + + if (xattrs) + g_variant_unref (xattrs); + + xattrs = g_variant_builder_end (builder); + g_variant_ref_sink (xattrs); + } + + *out_xattrs = g_steal_pointer (&xattrs); + return TRUE; +} + +/* XXX: add option in ctx->opts to disallow already existing dirs? see + * error_if_exist */ +static gboolean +aic_handle_dir (OstreeRepoArchiveImportContext *ctx, + OstreeMutableTree *parent, + const char *path, + GFileInfo *fi, + GCancellable *cancellable, + GError **error) +{ + const char *name = glnx_basename (path); + g_autoptr(GVariant) xattrs = NULL; + + if (!aic_get_xattrs (ctx, path, fi, &xattrs, cancellable, error)) + return FALSE; + + return mtree_ensure_dir_with_meta (ctx->repo, parent, name, fi, xattrs, + FALSE /* error_if_exist */, NULL, + cancellable, error); +} + +static gboolean +aic_write_file (OstreeRepoArchiveImportContext *ctx, + GFileInfo *fi, + GVariant *xattrs, + char **out_csum, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GInputStream) archive_stream = NULL; + g_autoptr(GInputStream) file_object_input = NULL; + guint64 length; + + g_autofree guchar *csum_raw = NULL; + + if (g_file_info_get_file_type (fi) == G_FILE_TYPE_REGULAR) + archive_stream = _ostree_libarchive_input_stream_new (ctx->archive); + + if (!ostree_raw_file_to_content_stream (archive_stream, fi, xattrs, + &file_object_input, &length, + cancellable, error)) + return FALSE; + + if (!ostree_repo_write_content (ctx->repo, NULL, file_object_input, length, + &csum_raw, cancellable, error)) + return FALSE; + + *out_csum = ostree_checksum_from_bytes (csum_raw); + return TRUE; +} + +static gboolean +aic_import_file (OstreeRepoArchiveImportContext *ctx, + OstreeMutableTree *parent, + const char *path, + GFileInfo *fi, + GCancellable *cancellable, + GError **error) +{ + const char *name = glnx_basename (path); + g_autoptr(GVariant) xattrs = NULL; + g_autofree char *csum = NULL; + + if (!aic_get_xattrs (ctx, path, fi, &xattrs, cancellable, error)) + return FALSE; + + if (!aic_write_file (ctx, fi, xattrs, &csum, cancellable, error)) + return FALSE; + + if (!ostree_mutable_tree_replace_file (parent, name, csum, error)) + return FALSE; + + return TRUE; +} + +static void +aic_add_deferred_hardlink (OstreeRepoArchiveImportContext *ctx, + const char *hardlink, + DeferredHardlink *dh) +{ + gboolean new_slist; + GSList *slist; + + slist = g_hash_table_lookup (ctx->deferred_hardlinks, hardlink); + new_slist = (slist == NULL); + + slist = g_slist_append (slist, dh); + + if (new_slist) + g_hash_table_insert (ctx->deferred_hardlinks, g_strdup (hardlink), slist); +} + +static void +aic_defer_hardlink (OstreeRepoArchiveImportContext *ctx, + OstreeMutableTree *parent, + const char *path, + guint64 size, + const char *hardlink) +{ + DeferredHardlink *dh = g_slice_new (DeferredHardlink); + dh->parent = g_object_ref (parent); + dh->path = g_strdup (path); + dh->size = size; + + aic_add_deferred_hardlink (ctx, hardlink, dh); +} + +static gboolean +aic_handle_file (OstreeRepoArchiveImportContext *ctx, + OstreeMutableTree *parent, + const char *path, + GFileInfo *fi, + GCancellable *cancellable, + GError **error) +{ + /* The wonderful world of hardlinks and archives. We have to be very careful + * here. Do not assume that if a file is a hardlink, it will have size 0 (e.g. + * cpio). Do not assume that if a file will have hardlinks to it, it will have + * size > 0. Also do not assume that its nlink param is present (tar) or even + * accurate (cpio). Also do not assume that hardlinks follow each other in + * order of entries. + * + * These archives were made to be extracted onto a filesystem, not directly + * hashed into an object store. So to be careful, we defer all hardlink + * imports until the very end. Nonzero files have to be imported, hardlink or + * not, since we can't easily seek back to this position later on. + * */ + + g_autofree char *hardlink = aic_get_final_entry_hardlink (ctx); + guint64 size = g_file_info_get_attribute_uint64 (fi, "standard::size"); + + if (hardlink == NULL || size > 0) + if (!aic_import_file (ctx, parent, path, fi, cancellable, error)) + return FALSE; + + if (hardlink) + aic_defer_hardlink (ctx, parent, path, size, hardlink); + + return TRUE; +} + +static gboolean +aic_handle_entry (OstreeRepoArchiveImportContext *ctx, + OstreeMutableTree *parent, + const char *path, + GFileInfo *fi, + GCancellable *cancellable, + GError **error) +{ + switch (g_file_info_get_file_type (fi)) + { + case G_FILE_TYPE_DIRECTORY: + return aic_handle_dir (ctx, parent, path, fi, cancellable, error); + case G_FILE_TYPE_REGULAR: + case G_FILE_TYPE_SYMBOLIC_LINK: + return aic_handle_file (ctx, parent, path, fi, cancellable, error); + default: + if (ctx->opts->ignore_unsupported_content) + return TRUE; + else + { + return glnx_throw (error, "Unsupported file type for path \"%s\"", + path); + } + } +} + +static gboolean +aic_import_entry (OstreeRepoArchiveImportContext *ctx, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *path = aic_get_final_entry_pathname (ctx, error); + + if (path == NULL) + return FALSE; + + g_autoptr(GFileInfo) fi = NULL; + if (aic_apply_modifier_filter (ctx, path, &fi) + == OSTREE_REPO_COMMIT_FILTER_SKIP) + return TRUE; + + g_autoptr(OstreeMutableTree) parent = NULL; + if (!aic_get_parent_dir (ctx, path, &parent, cancellable, error)) + return FALSE; + + return aic_handle_entry (ctx, parent, path, fi, cancellable, error); +} + +static gboolean +aic_import_from_hardlink (OstreeRepoArchiveImportContext *ctx, + const char *target, + DeferredHardlink *dh, + GError **error) +{ + g_autofree char *csum = NULL; + const char *name = glnx_basename (target); + const char *name_dh = glnx_basename (dh->path); + g_autoptr(GPtrArray) components = NULL; + g_autoptr(OstreeMutableTree) parent = NULL; + + if (!ostree_mutable_tree_lookup (dh->parent, name_dh, &csum, NULL, error)) + return FALSE; + + g_assert (csum); + + if (!ot_util_path_split_validate (target, &components, error)) + return FALSE; + + if (!ostree_mutable_tree_walk (ctx->root, components, 0, &parent, error)) + return FALSE; + + if (!ostree_mutable_tree_replace_file (parent, name, csum, error)) + return FALSE; + + return TRUE; +} + +static gboolean +aic_lookup_file_csum (OstreeRepoArchiveImportContext *ctx, + const char *target, + char **out_csum, + GError **error) +{ + g_autofree char *csum = NULL; + const char *name = glnx_basename (target); + g_autoptr(OstreeMutableTree) parent = NULL; + g_autoptr(OstreeMutableTree) subdir = NULL; + g_autoptr(GPtrArray) components = NULL; + + if (!ot_util_path_split_validate (target, &components, error)) + return FALSE; + + if (!ostree_mutable_tree_walk (ctx->root, components, 0, &parent, error)) + return FALSE; + + if (!ostree_mutable_tree_lookup (parent, name, &csum, &subdir, error)) + return FALSE; + + if (subdir != NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Expected hardlink file target at \"%s\" but found a " + "directory", target); + return FALSE; + } + + *out_csum = g_steal_pointer (&csum); + return TRUE; +} + +static gboolean +aic_import_deferred_hardlinks_for (OstreeRepoArchiveImportContext *ctx, + const char *target, + GSList *hardlinks, + GError **error) +{ + GSList *payload = hardlinks; + g_autofree char *csum = NULL; + + /* find node with the payload, if any (if none, then they're all hardlinks to + * a zero sized target, and there's no rewrite required) */ + while (payload && ((DeferredHardlink*)payload->data)->size == 0) + payload = g_slist_next (payload); + + /* rewrite the target so it points to the csum of the payload hardlink */ + if (payload) + if (!aic_import_from_hardlink (ctx, target, payload->data, error)) + return FALSE; + + if (!aic_lookup_file_csum (ctx, target, &csum, error)) + return FALSE; + + /* import all the hardlinks */ + for (GSList *hl = hardlinks; hl != NULL; hl = g_slist_next (hl)) + { + DeferredHardlink *df = hl->data; + const char *name = glnx_basename (df->path); + + if (hl == payload) + continue; /* small optimization; no need to redo this one */ + + if (!ostree_mutable_tree_replace_file (df->parent, name, csum, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +aic_import_deferred_hardlinks (OstreeRepoArchiveImportContext *ctx, + GCancellable *cancellable, + GError **error) +{ + GLNX_HASH_TABLE_FOREACH_KV (ctx->deferred_hardlinks, const char*, target, GSList*, links) + { + if (!aic_import_deferred_hardlinks_for (ctx, target, links, error)) + return FALSE; + } + return TRUE; +} + +static void +deferred_hardlink_free (void *data) +{ + DeferredHardlink *dh = data; + g_object_unref (dh->parent); + g_free (dh->path); + g_slice_free (DeferredHardlink, dh); +} + +static void +deferred_hardlinks_list_free (void *data) +{ + GSList *slist = data; + g_slist_free_full (slist, deferred_hardlink_free); +} +#endif /* HAVE_LIBARCHIVE */ + +/** + * ostree_repo_import_archive_to_mtree: (skip) + * @self: An #OstreeRepo + * @opts: Options structure, ensure this is zeroed, then set specific variables + * @archive: Really this is "struct archive*" + * @mtree: The #OstreeMutableTree to write to + * @modifier: (allow-none): Optional commit modifier + * @cancellable: Cancellable + * @error: Error + * + * Import an archive file @archive into the repository, and write its + * file structure to @mtree. + */ +gboolean +ostree_repo_import_archive_to_mtree (OstreeRepo *self, + OstreeRepoImportArchiveOptions *opts, + void *archive, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_LIBARCHIVE + gboolean ret = FALSE; + struct archive *a = archive; + g_autoptr(GHashTable) deferred_hardlinks = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + deferred_hardlinks_list_free); + + OstreeRepoArchiveImportContext aictx = { + .repo = self, + .opts = opts, + .root = mtree, + .archive = archive, + .deferred_hardlinks = deferred_hardlinks, + .modifier = modifier + }; + + _ostree_repo_setup_generate_sizes (self, modifier); + + while (TRUE) + { + int r = archive_read_next_header (a, &aictx.entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) + { + propagate_libarchive_error (error, a); + goto out; + } + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + goto out; + + if (!aic_import_entry (&aictx, cancellable, error)) + goto out; + } + + if (!aic_import_deferred_hardlinks (&aictx, cancellable, error)) + goto out; + + /* If we didn't import anything at all, and autocreation of parents + * is enabled, automatically create a root directory. This is + * useful primarily when importing Docker image layers, which can + * just be metadata. + */ + if (opts->autocreate_parents && + ostree_mutable_tree_get_metadata_checksum (mtree) == NULL) + { + /* _ostree_stbuf_to_gfileinfo() only looks at these fields, + * but we use it to ensure it sets all of the relevant GFileInfo + * properties. + */ + struct stat stbuf = { .st_mode = DEFAULT_DIRMODE, + .st_uid = 0, + .st_gid = 0 }; + g_autoptr(GFileInfo) fi = _ostree_stbuf_to_gfileinfo (&stbuf); + + g_autoptr(GFileInfo) mfi = NULL; + (void)_ostree_repo_commit_modifier_apply (self, modifier, "/", + fi, &mfi); + + if (!aic_ensure_parent_dir_with_file_info (&aictx, mtree, "/", mfi, NULL, + cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree is not compiled with libarchive support"); + return FALSE; +#endif +} + +#ifdef HAVE_LIBARCHIVE +static gboolean +write_archive_to_mtree (OstreeRepo *self, + OtAutoArchiveRead *archive, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + gboolean autocreate_parents, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + OstreeRepoImportArchiveOptions opts = { 0, }; + + opts.autocreate_parents = !!autocreate_parents; + + if (!ostree_repo_import_archive_to_mtree (self, &opts, archive, mtree, modifier, cancellable, error)) + goto out; + + if (archive_read_close (archive) != ARCHIVE_OK) + { + propagate_libarchive_error (error, archive); + goto out; + } + + ret = TRUE; + out: + (void)archive_read_close (archive); + return ret; +} +#endif + +/** + * ostree_repo_write_archive_to_mtree: + * @self: An #OstreeRepo + * @archive: A path to an archive file + * @mtree: The #OstreeMutableTree to write to + * @modifier: (allow-none): Optional commit modifier + * @autocreate_parents: Autocreate parent directories + * @cancellable: Cancellable + * @error: Error + * + * Import an archive file @archive into the repository, and write its + * file structure to @mtree. + */ +gboolean +ostree_repo_write_archive_to_mtree (OstreeRepo *self, + GFile *archive, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + gboolean autocreate_parents, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_LIBARCHIVE + g_autoptr(OtAutoArchiveRead) a = ot_open_archive_read (gs_file_get_path_cached (archive), error); + if (a) + return write_archive_to_mtree (self, a, mtree, modifier, autocreate_parents, cancellable, error); + + return FALSE; +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree is not compiled with libarchive support"); + return FALSE; +#endif +} + +/** + * ostree_repo_write_archive_to_mtree_from_fd: + * @self: An #OstreeRepo + * @fd: A file descriptor to read the archive from + * @mtree: The #OstreeMutableTree to write to + * @modifier: (allow-none): Optional commit modifier + * @autocreate_parents: Autocreate parent directories + * @cancellable: Cancellable + * @error: Error + * + * Read an archive from @fd and import it into the repository, writing + * its file structure to @mtree. + */ +gboolean +ostree_repo_write_archive_to_mtree_from_fd (OstreeRepo *self, + int fd, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + gboolean autocreate_parents, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_LIBARCHIVE + g_autoptr(OtAutoArchiveRead) a = ot_open_archive_read_fd (fd, error); + if (a) + return write_archive_to_mtree (self, a, mtree, modifier, autocreate_parents, cancellable, error); + + return FALSE; +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree is not compiled with libarchive support"); + return FALSE; +#endif +} + +#ifdef HAVE_LIBARCHIVE + +static gboolean +file_to_archive_entry_common (GFile *root, + OstreeRepoExportArchiveOptions *opts, + GFile *path, + GFileInfo *file_info, + struct archive_entry *entry, + GError **error) +{ + gboolean ret = FALSE; + g_autofree char *pathstr = g_file_get_relative_path (root, path); + g_autoptr(GVariant) xattrs = NULL; + time_t ts = (time_t) opts->timestamp_secs; + + if (opts->path_prefix && opts->path_prefix[0]) + { + g_autofree char *old_pathstr = pathstr; + pathstr = g_strconcat (opts->path_prefix, old_pathstr, NULL); + } + + if (pathstr == NULL || !pathstr[0]) + { + g_free (pathstr); + pathstr = g_strdup ("."); + } + + archive_entry_update_pathname_utf8 (entry, pathstr); + archive_entry_set_ctime (entry, ts, OSTREE_TIMESTAMP); + archive_entry_set_mtime (entry, ts, OSTREE_TIMESTAMP); + archive_entry_set_atime (entry, ts, OSTREE_TIMESTAMP); + archive_entry_set_uid (entry, g_file_info_get_attribute_uint32 (file_info, "unix::uid")); + archive_entry_set_gid (entry, g_file_info_get_attribute_uint32 (file_info, "unix::gid")); + archive_entry_set_mode (entry, g_file_info_get_attribute_uint32 (file_info, "unix::mode")); + + if (!ostree_repo_file_get_xattrs ((OstreeRepoFile*)path, &xattrs, NULL, error)) + goto out; + + if (!opts->disable_xattrs) + { + int i, n; + + n = g_variant_n_children (xattrs); + for (i = 0; i < n; i++) + { + const guint8* name; + g_autoptr(GVariant) value = NULL; + const guint8* value_data; + gsize value_len; + + g_variant_get_child (xattrs, i, "(^&ay@ay)", &name, &value); + value_data = g_variant_get_fixed_array (value, &value_len, 1); + + archive_entry_xattr_add_entry (entry, (char*)name, + (char*) value_data, value_len); + } + } + + ret = TRUE; + out: + return ret; +} + +static gboolean +write_header_free_entry (struct archive *a, + struct archive_entry **entryp, + GError **error) +{ + struct archive_entry *entry = *entryp; + gboolean ret = FALSE; + + if (archive_write_header (a, entry) != ARCHIVE_OK) + { + propagate_libarchive_error (error, a); + goto out; + } + + ret = TRUE; + out: + archive_entry_free (entry); + *entryp = NULL; + return ret; +} + +static gboolean +write_directory_to_libarchive_recurse (OstreeRepo *self, + OstreeRepoExportArchiveOptions *opts, + GFile *root, + GFile *dir, + struct archive *a, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GFileInfo) dir_info = NULL; + g_autoptr(GFileEnumerator) dir_enum = NULL; + struct archive_entry *entry = NULL; + + dir_info = g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!dir_info) + goto out; + + entry = archive_entry_new2 (a); + if (!file_to_archive_entry_common (root, opts, dir, dir_info, entry, error)) + goto out; + if (!write_header_free_entry (a, &entry, error)) + goto out; + + dir_enum = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!dir_enum) + goto out; + + while (TRUE) + { + GFileInfo *file_info; + GFile *path; + + if (!g_file_enumerator_iterate (dir_enum, &file_info, &path, + cancellable, error)) + goto out; + if (file_info == NULL) + break; + + /* First, handle directories recursively */ + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) + { + if (!write_directory_to_libarchive_recurse (self, opts, root, path, a, + cancellable, error)) + goto out; + + /* Go to the next entry */ + continue; + } + + /* Past here, should be a regular file or a symlink */ + + entry = archive_entry_new2 (a); + if (!file_to_archive_entry_common (root, opts, path, file_info, entry, error)) + goto out; + + switch (g_file_info_get_file_type (file_info)) + { + case G_FILE_TYPE_SYMBOLIC_LINK: + { + archive_entry_set_symlink (entry, g_file_info_get_symlink_target (file_info)); + if (!write_header_free_entry (a, &entry, error)) + goto out; + } + break; + case G_FILE_TYPE_REGULAR: + { + guint8 buf[8192]; + g_autoptr(GInputStream) file_in = NULL; + g_autoptr(GFileInfo) file_info = NULL; + const char *checksum; + + checksum = ostree_repo_file_get_checksum ((OstreeRepoFile*)path); + + if (!ostree_repo_load_file (self, checksum, &file_in, &file_info, NULL, + cancellable, error)) + goto out; + + archive_entry_set_size (entry, g_file_info_get_size (file_info)); + + if (archive_write_header (a, entry) != ARCHIVE_OK) + { + propagate_libarchive_error (error, a); + goto out; + } + + while (TRUE) + { + gssize bytes_read = g_input_stream_read (file_in, buf, sizeof (buf), + cancellable, error); + if (bytes_read < 0) + goto out; + if (bytes_read == 0) + break; + + { ssize_t r = archive_write_data (a, buf, bytes_read); + if (r != bytes_read) + { + propagate_libarchive_error (error, a); + g_prefix_error (error, "Failed to write %" G_GUINT64_FORMAT " bytes (code %" G_GUINT64_FORMAT"): ", (guint64)bytes_read, (guint64)r); + goto out; + } + } + } + + if (archive_write_finish_entry (a) != ARCHIVE_OK) + { + propagate_libarchive_error (error, a); + goto out; + } + + archive_entry_free (entry); + entry = NULL; + } + break; + default: + g_assert_not_reached (); + } + } + + ret = TRUE; + out: + if (entry) + archive_entry_free (entry); + return ret; +} +#endif + +/** + * ostree_repo_export_tree_to_archive: (skip) + * @self: An #OstreeRepo + * @opts: Options controlling conversion + * @root: An #OstreeRepoFile for the base directory + * @archive: A `struct archive`, but specified as void to avoid a dependency on the libarchive headers + * @cancellable: Cancellable + * @error: Error + * + * Import an archive file @archive into the repository, and write its + * file structure to @mtree. + */ +gboolean +ostree_repo_export_tree_to_archive (OstreeRepo *self, + OstreeRepoExportArchiveOptions *opts, + OstreeRepoFile *root, + void *archive, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_LIBARCHIVE + gboolean ret = FALSE; + struct archive *a = archive; + + if (!write_directory_to_libarchive_recurse (self, opts, (GFile*)root, (GFile*)root, + a, cancellable, error)) + goto out; + + ret = TRUE; + out: + return ret; +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree is not compiled with libarchive support"); + return FALSE; +#endif +} diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h new file mode 100644 index 0000000..8c1f507 --- /dev/null +++ b/src/libostree/ostree-repo-private.h @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include "config.h" +#include "otutil.h" +#include "ostree-ref.h" +#include "ostree-repo.h" +#include "ostree-remote-private.h" + +G_BEGIN_DECLS + +#define OSTREE_DELTAPART_VERSION (0) + +#define _OSTREE_SUMMARY_CACHE_DIR "summaries" +#define _OSTREE_CACHE_DIR "cache" + +#define _OSTREE_MAX_OUTSTANDING_FETCHER_REQUESTS 8 +#define _OSTREE_MAX_OUTSTANDING_DELTAPART_REQUESTS 2 + +/* We want some parallelism with disk writes, but we also + * want to avoid starting tens or hundreds of threads + * (via GTask) all writing to disk. Eventually we may + * use io_uring which handles backpressure correctly. + * Also, in "immediate fsync" mode, this helps provide + * much more backpressure, helping our I/O patterns + * be nicer for any concurrent processes, such as etcd + * or other databases. + * https://github.com/openshift/machine-config-operator/issues/1897 + * */ +#define _OSTREE_MAX_OUTSTANDING_WRITE_REQUESTS 3 + +/* Well-known keys for the additional metadata field in a summary file. */ +#define OSTREE_SUMMARY_LAST_MODIFIED "ostree.summary.last-modified" +#define OSTREE_SUMMARY_EXPIRES "ostree.summary.expires" +#define OSTREE_SUMMARY_COLLECTION_ID "ostree.summary.collection-id" +#define OSTREE_SUMMARY_COLLECTION_MAP "ostree.summary.collection-map" + +#define _OSTREE_PAYLOAD_LINK_PREFIX "../" +#define _OSTREE_PAYLOAD_LINK_PREFIX_LEN (sizeof (_OSTREE_PAYLOAD_LINK_PREFIX) - 1) + +/* Well-known keys for the additional metadata field in a commit in a ref entry + * in a summary file. */ +#define OSTREE_COMMIT_TIMESTAMP "ostree.commit.timestamp" + +typedef enum { + OSTREE_REPO_TEST_ERROR_PRE_COMMIT = (1 << 0), + OSTREE_REPO_TEST_ERROR_INVALID_CACHE = (1 << 1), +} OstreeRepoTestErrorFlags; + +struct OstreeRepoCommitModifier { + volatile gint refcount; + + OstreeRepoCommitModifierFlags flags; + OstreeRepoCommitFilter filter; + gpointer user_data; + GDestroyNotify destroy_notify; + + OstreeRepoCommitModifierXattrCallback xattr_callback; + GDestroyNotify xattr_destroy; + gpointer xattr_user_data; + + GLnxTmpDir sepolicy_tmpdir; + OstreeSePolicy *sepolicy; + GHashTable *devino_cache; +}; + +typedef enum { + OSTREE_REPO_SYSROOT_KIND_UNKNOWN, + OSTREE_REPO_SYSROOT_KIND_NO, /* Not a system repo */ + OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT, /* Constructed via ostree_sysroot_get_repo() */ + OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE, /* We match /ostree/repo */ +} OstreeRepoSysrootKind; + +typedef struct { + GHashTable *refs; /* (element-type utf8 utf8) */ + GHashTable *collection_refs; /* (element-type OstreeCollectionRef utf8) */ + OstreeRepoTransactionStats stats; + /* Implementation of min-free-space-percent */ + gulong blocksize; + fsblkcnt_t max_blocks; +} OstreeRepoTxn; + +typedef enum { + _OSTREE_FEATURE_NO, + _OSTREE_FEATURE_MAYBE, + _OSTREE_FEATURE_YES, +} _OstreeFeatureSupport; + +/** + * OstreeRepo: + * + * Private instance structure. + */ +struct OstreeRepo { + GObject parent; + + char *stagedir_prefix; + GLnxTmpDir commit_stagedir; + GLnxLockFile commit_stagedir_lock; + + /* A cached fd-relative version, distinct from the case where we may have a + * user-provided absolute path. + */ + GFile *repodir_fdrel; + GFile *repodir; /* May be %NULL if we were opened via ostree_repo_open_at() */ + int repo_dir_fd; + int tmp_dir_fd; + int cache_dir_fd; + char *cache_dir; + int objects_dir_fd; + int uncompressed_objects_dir_fd; + GFile *sysroot_dir; + GWeakRef sysroot; /* Weak to avoid a circular ref; see also `is_system` */ + char *remotes_config_dir; + + GMutex txn_lock; + OstreeRepoTxn txn; + gboolean txn_locked; + _OstreeFeatureSupport fs_verity_wanted; + _OstreeFeatureSupport fs_verity_supported; + + GMutex cache_lock; + guint dirmeta_cache_refcount; + /* char * checksum → GVariant * for dirmeta objects, used in the checkout path */ + GHashTable *dirmeta_cache; + + gboolean inited; + gboolean writable; + OstreeRepoSysrootKind sysroot_kind; + GError *writable_error; + gboolean in_transaction; + gboolean disable_fsync; + gboolean per_object_fsync; + gboolean disable_xattrs; + guint zlib_compression_level; + GHashTable *loose_object_devino_hash; + GHashTable *updated_uncompressed_dirs; + + /* FIXME: The object sizes hash table is really per-commit state, not repo + * state. Using a single table for the repo means that commits cannot be + * built simultaneously if they're adding size information. This data should + * probably be in OstreeMutableTree, but that's gone by the time the actual + * commit is constructed. At that point the only commit state is in the root + * OstreeRepoFile. + */ + GHashTable *object_sizes; + + /* Cache the repo's device/inode to use for comparisons elsewhere */ + dev_t device; + ino_t inode; + uid_t owner_uid; /* Cache of repo's owner uid */ + guint min_free_space_percent; /* See the min-free-space-percent config option */ + guint64 min_free_space_mb; /* See the min-free-space-size config option */ + guint64 reserved_blocks; + gboolean cleanup_stagedir; + + guint test_error_flags; /* OstreeRepoTestErrorFlags */ + + GKeyFile *config; + GHashTable *remotes; + GMutex remotes_lock; + OstreeRepoMode mode; + gboolean enable_uncompressed_cache; + gboolean generate_sizes; + guint64 tmp_expiry_seconds; + gchar *collection_id; + gboolean add_remotes_config_dir; /* Add new remotes in remotes.d dir */ + gint lock_timeout_seconds; + guint64 payload_link_threshold; + gint fs_support_reflink; /* The underlying filesystem has support for ioctl (FICLONE..) */ + gchar **repo_finders; + gchar *bootloader; /* Configure which bootloader to use. */ + + OstreeRepo *parent_repo; +}; + +/* Taken from flatpak; may be made into public API later */ +typedef OstreeRepo _OstreeRepoAutoTransaction; +static inline void +_ostree_repo_auto_transaction_cleanup (void *p) +{ + OstreeRepo *repo = p; + if (repo) + (void) ostree_repo_abort_transaction (repo, NULL, NULL); +} + +static inline _OstreeRepoAutoTransaction * +_ostree_repo_auto_transaction_start (OstreeRepo *repo, + GCancellable *cancellable, + GError **error) +{ + if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) + return NULL; + return (_OstreeRepoAutoTransaction *)repo; +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (_OstreeRepoAutoTransaction, _ostree_repo_auto_transaction_cleanup) + +typedef struct { + dev_t dev; + ino_t ino; + char checksum[OSTREE_SHA256_STRING_LEN+1]; +} OstreeDevIno; + +/* A MemoryCacheRef is an in-memory cache of objects (currently just DIRMETA). This can + * be used when performing an operation that traverses a repository in someway. Currently, + * the primary use case is ostree_repo_checkout_at() avoiding lots of duplicate dirmeta + * lookups. + */ +typedef struct { + OstreeRepo *repo; +} OstreeRepoMemoryCacheRef; + + +void +_ostree_repo_memory_cache_ref_init (OstreeRepoMemoryCacheRef *state, + OstreeRepo *repo); + +void +_ostree_repo_memory_cache_ref_destroy (OstreeRepoMemoryCacheRef *state); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoMemoryCacheRef, _ostree_repo_memory_cache_ref_destroy) + +#define OSTREE_REPO_TMPDIR_STAGING "staging-" + +gboolean +_ostree_repo_allocate_tmpdir (int tmpdir_dfd, + const char *tmpdir_prefix, + GLnxTmpDir *tmpdir_out, + GLnxLockFile *file_lock_out, + gboolean * reusing_dir_out, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_has_staging_prefix (const char *filename); + +gboolean +_ostree_repo_try_lock_tmpdir (int tmpdir_dfd, + const char *tmpdir_name, + GLnxLockFile *file_lock_out, + gboolean *out_did_lock, + GError **error); + +gboolean +_ostree_repo_ensure_loose_objdir_at (int dfd, + const char *loose_path, + GCancellable *cancellable, + GError **error); + +GFile * +_ostree_repo_get_commit_metadata_loose_path (OstreeRepo *self, + const char *checksum); + +gboolean +_ostree_repo_has_loose_object (OstreeRepo *self, + const char *checksum, + OstreeObjectType objtype, + gboolean *out_is_stored, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_write_bareuser_metadata (int fd, + guint32 uid, + guint32 gid, + guint32 mode, + GVariant *xattrs, + GError **error); + +gboolean +_ostree_repo_write_directory_meta (OstreeRepo *self, + GFileInfo *file_info, + GVariant *xattrs, + guchar **out_csum, + GCancellable *cancellable, + GError **error); +gboolean +_ostree_repo_update_refs (OstreeRepo *self, + GHashTable *refs, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_update_collection_refs (OstreeRepo *self, + GHashTable *refs, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_file_replace_contents (OstreeRepo *self, + int dfd, + const char *path, + const guint8 *buf, + gsize len, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_write_ref (OstreeRepo *self, + const char *remote, + const OstreeCollectionRef *ref, + const char *rev, + const char *alias, + GCancellable *cancellable, + GError **error); + +OstreeRepoFile * +_ostree_repo_file_new_for_commit (OstreeRepo *repo, + const char *commit, + GError **error); + +OstreeRepoFile * +_ostree_repo_file_new_root (OstreeRepo *repo, + const char *contents_checksum, + const char *metadata_checksum); + +gboolean +_ostree_repo_traverse_dirtree_internal (OstreeRepo *repo, + const char *dirtree_checksum, + int recursion_depth, + GHashTable *inout_reachable, + GHashTable *inout_content_names, + GCancellable *cancellable, + GError **error); + +OstreeRepoCommitFilterResult +_ostree_repo_commit_modifier_apply (OstreeRepo *self, + OstreeRepoCommitModifier *modifier, + const char *path, + GFileInfo *file_info, + GFileInfo **out_modified_info); + +void +_ostree_repo_setup_generate_sizes (OstreeRepo *self, + OstreeRepoCommitModifier *modifier); + +gboolean +_ostree_repo_remote_name_is_file (const char *remote_name); + +#ifndef OSTREE_DISABLE_GPGME +OstreeGpgVerifyResult * +_ostree_repo_gpg_verify_with_metadata (OstreeRepo *self, + GBytes *signed_data, + GVariant *metadata, + const char *remote_name, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error); + +OstreeGpgVerifyResult * +_ostree_repo_verify_commit_internal (OstreeRepo *self, + const char *commit_checksum, + const char *remote_name, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error); +#endif /* OSTREE_DISABLE_GPGME */ + +typedef enum { + _OSTREE_REPO_IMPORT_FLAGS_NONE = 0, + _OSTREE_REPO_IMPORT_FLAGS_TRUSTED = (1 << 0), + _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY = (1 << 1), +} OstreeRepoImportFlags; + +gboolean +_ostree_repo_import_object (OstreeRepo *self, + OstreeRepo *source, + OstreeObjectType objtype, + const char *checksum, + OstreeRepoImportFlags flags, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_commit_tmpf_final (OstreeRepo *self, + const char *checksum, + OstreeObjectType objtype, + GLnxTmpfile *tmpf, + GCancellable *cancellable, + GError **error); + +typedef struct { + gboolean initialized; + gpointer opaque0[10]; + guint opaque1[10]; +} OstreeRepoBareContent; +void _ostree_repo_bare_content_cleanup (OstreeRepoBareContent *regwrite); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoBareContent, _ostree_repo_bare_content_cleanup) + +gboolean +_ostree_repo_bare_content_open (OstreeRepo *self, + const char *checksum, + guint64 content_len, + guint uid, + guint gid, + guint mode, + GVariant *xattrs, + OstreeRepoBareContent *out_regwrite, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_bare_content_write (OstreeRepo *repo, + OstreeRepoBareContent *barewrite, + const guint8 *buf, + size_t len, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_bare_content_commit (OstreeRepo *self, + OstreeRepoBareContent *barewrite, + char *checksum_buf, + size_t buflen, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_load_file_bare (OstreeRepo *self, + const char *checksum, + int *out_fd, + struct stat *out_stbuf, + char **out_symlink, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_update_mtime (OstreeRepo *self, + GError **error); + +gboolean +_ostree_repo_add_remote (OstreeRepo *self, + OstreeRemote *remote); +gboolean +_ostree_repo_remove_remote (OstreeRepo *self, + OstreeRemote *remote); +OstreeRemote * +_ostree_repo_get_remote (OstreeRepo *self, + const char *name, + GError **error); +OstreeRemote * +_ostree_repo_get_remote_inherited (OstreeRepo *self, + const char *name, + GError **error); + +gboolean +_ostree_repo_maybe_regenerate_summary (OstreeRepo *self, + GCancellable *cancellable, + GError **error); + +/* Locking APIs are currently private. + * See https://github.com/ostreedev/ostree/pull/1555 + */ +typedef enum { + OSTREE_REPO_LOCK_SHARED, + OSTREE_REPO_LOCK_EXCLUSIVE +} OstreeRepoLockType; + +gboolean _ostree_repo_lock_push (OstreeRepo *self, + OstreeRepoLockType lock_type, + GCancellable *cancellable, + GError **error); +gboolean _ostree_repo_lock_pop (OstreeRepo *self, + GCancellable *cancellable, + GError **error); + +typedef OstreeRepo OstreeRepoAutoLock; + +OstreeRepoAutoLock * _ostree_repo_auto_lock_push (OstreeRepo *self, + OstreeRepoLockType lock_type, + GCancellable *cancellable, + GError **error); +void _ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, _ostree_repo_auto_lock_cleanup) + +gboolean +_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf, + _OstreeFeatureSupport fsverity_requested, + gboolean *supported, + GError **error); + +gboolean +_ostree_tmpf_fsverity (OstreeRepo *self, + GLnxTmpfile *tmpf, + GError **error); + +gboolean +_ostree_repo_verify_bindings (const char *collection_id, + const char *ref_name, + GVariant *commit, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-prune.c b/src/libostree/ostree-repo-prune.c new file mode 100644 index 0000000..0b95362 --- /dev/null +++ b/src/libostree/ostree-repo-prune.c @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ostree-core-private.h" +#include "ostree-repo-private.h" +#include "ostree-autocleanups.h" +#include "otutil.h" + +typedef struct { + OstreeRepo *repo; + GHashTable *reachable; + guint n_reachable_meta; + guint n_reachable_content; + guint n_unreachable_meta; + guint n_unreachable_content; + guint64 freed_bytes; +} OtPruneData; + +static gboolean +maybe_prune_loose_object (OtPruneData *data, + OstreeRepoPruneFlags flags, + const char *checksum, + OstreeObjectType objtype, + GCancellable *cancellable, + GError **error) +{ + gboolean reachable = FALSE; + g_autoptr(GVariant) key = NULL; + + key = ostree_object_name_serialize (checksum, objtype); + + if (g_hash_table_lookup_extended (data->reachable, key, NULL, NULL)) + reachable = TRUE; + else + { + guint64 storage_size = 0; + + g_debug ("Pruning unneeded object %s.%s", checksum, + ostree_object_type_to_string (objtype)); + + if (!ostree_repo_query_object_storage_size (data->repo, objtype, checksum, + &storage_size, cancellable, error)) + return FALSE; + + data->freed_bytes += storage_size; + + if (!(flags & OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE)) + { + if (objtype == OSTREE_OBJECT_TYPE_PAYLOAD_LINK) + { + ssize_t size; + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + char target_checksum[OSTREE_SHA256_STRING_LEN+1]; + char target_buf[_OSTREE_LOOSE_PATH_MAX + _OSTREE_PAYLOAD_LINK_PREFIX_LEN]; + + _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, data->repo->mode); + size = readlinkat (data->repo->objects_dir_fd, loose_path_buf, target_buf, sizeof (target_buf)); + if (size < 0) + return glnx_throw_errno_prefix (error, "readlinkat"); + + if (size < OSTREE_SHA256_STRING_LEN + _OSTREE_PAYLOAD_LINK_PREFIX_LEN) + return glnx_throw (error, "invalid data size for %s", loose_path_buf); + + sprintf (target_checksum, "%.2s%.62s", target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN, target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN + 3); + + g_autoptr(GVariant) target_key = ostree_object_name_serialize (target_checksum, OSTREE_OBJECT_TYPE_FILE); + + if (g_hash_table_lookup_extended (data->reachable, target_key, NULL, NULL)) + { + guint64 target_storage_size = 0; + if (!ostree_repo_query_object_storage_size (data->repo, OSTREE_OBJECT_TYPE_FILE, target_checksum, + &target_storage_size, cancellable, error)) + return FALSE; + + reachable = target_storage_size >= data->repo->payload_link_threshold; + if (reachable) + goto exit; + } + } + else if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + if (!ostree_repo_mark_commit_partial (data->repo, checksum, FALSE, error)) + return FALSE; + } + + if (!ostree_repo_delete_object (data->repo, objtype, checksum, + cancellable, error)) + return FALSE; + + } + + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + data->n_unreachable_meta++; + else + data->n_unreachable_content++; + } + + exit: + if (reachable) + { + g_debug ("Keeping needed object %s.%s", checksum, + ostree_object_type_to_string (objtype)); + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + data->n_reachable_meta++; + else + data->n_reachable_content++; + } + + return TRUE; +} + +static gboolean +_ostree_repo_prune_tmp (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + if (self->cache_dir_fd == -1) + return TRUE; + + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (self->cache_dir_fd, _OSTREE_SUMMARY_CACHE_DIR, + &dfd_iter, &exists, error)) + return FALSE; + /* Note early return */ + if (!exists) + return TRUE; + + while (TRUE) + { + size_t len; + gboolean has_sig_suffix = FALSE; + struct dirent *dent; + g_autofree gchar *d_name = NULL; + + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + /* dirent->d_name can't be modified directly; see `man 3 readdir` */ + d_name = g_strdup (dent->d_name); + len = strlen (d_name); + if (len > 4 && g_strcmp0 (d_name + len - 4, ".sig") == 0) + { + has_sig_suffix = TRUE; + d_name[len - 4] = '\0'; + } + + if (!g_hash_table_contains (self->remotes, d_name)) + { + /* Restore the previous value to get the file name. */ + if (has_sig_suffix) + d_name[len - 4] = '.'; + + if (!glnx_unlinkat (dfd_iter.fd, d_name, 0, error)) + return FALSE; + } + } + + return TRUE; +} + + +/** + * ostree_repo_prune_static_deltas: + * @self: Repo + * @commit: (allow-none): ASCII SHA256 checksum for commit, or %NULL for each + * non existing commit + * @cancellable: Cancellable + * @error: Error + * + * Prune static deltas, if COMMIT is specified then delete static delta files only + * targeting that commit; otherwise any static delta of non existing commits are + * deleted. + * + * Locking: exclusive + */ +gboolean +ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepoAutoLock) lock = + _ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error); + if (!lock) + return FALSE; + + g_autoptr(GPtrArray) deltas = NULL; + if (!ostree_repo_list_static_delta_names (self, &deltas, + cancellable, error)) + return FALSE; + + for (guint i = 0; i < deltas->len; i++) + { + const char *deltaname = deltas->pdata[i]; + const char *dash = strchr (deltaname, '-'); + const char *to = NULL; + g_autofree char *from = NULL; + + if (!dash) + { + to = deltaname; + } + else + { + from = g_strndup (deltaname, dash - deltaname); + to = dash + 1; + } + + if (commit) + { + if (g_strcmp0 (to, commit)) + continue; + } + else + { + gboolean have_commit; + if (!ostree_repo_has_object (self, OSTREE_OBJECT_TYPE_COMMIT, + to, &have_commit, + cancellable, error)) + return FALSE; + + if (have_commit) + continue; + } + + g_debug ("Trying to prune static delta %s", deltaname); + g_autofree char *deltadir = _ostree_get_relative_static_delta_path (from, to, NULL); + if (!glnx_shutil_rm_rf_at (self->repo_dir_fd, deltadir, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +repo_prune_internal (OstreeRepo *self, + GHashTable *objects, + OstreeRepoPruneOptions *options, + gint *out_objects_total, + gint *out_objects_pruned, + guint64 *out_pruned_object_size_total, + GCancellable *cancellable, + GError **error) +{ + OtPruneData data = { 0, }; + + data.repo = self; + /* We unref this when we're done */ + g_autoptr(GHashTable) reachable_owned = g_hash_table_ref (options->reachable); + data.reachable = reachable_owned; + + GLNX_HASH_TABLE_FOREACH_KV (objects, GVariant*, serialized_key, GVariant*, objdata) + { + const char *checksum; + OstreeObjectType objtype; + gboolean is_loose; + + ostree_object_name_deserialize (serialized_key, &checksum, &objtype); + g_variant_get_child (objdata, 0, "b", &is_loose); + + if (!is_loose) + continue; + + if (!maybe_prune_loose_object (&data, options->flags, checksum, objtype, + cancellable, error)) + return FALSE; + } + + if (!ostree_repo_prune_static_deltas (self, NULL, cancellable, error)) + return FALSE; + + if (!_ostree_repo_prune_tmp (self, cancellable, error)) + return FALSE; + + *out_objects_total = (data.n_reachable_meta + data.n_unreachable_meta + + data.n_reachable_content + data.n_unreachable_content); + *out_objects_pruned = (data.n_unreachable_meta + data.n_unreachable_content); + *out_pruned_object_size_total = data.freed_bytes; + return TRUE; +} + +/** + * ostree_repo_traverse_reachable_refs: + * @self: Repo + * @depth: Depth of traversal + * @reachable: (element-type GVariant GVariant): Set of reachable objects (will be modified) + * @cancellable: Cancellable + * @error: Error + * + * Add all commit objects directly reachable via a ref to @reachable. + * + * Locking: shared + * Since: 2018.6 + */ +gboolean +ostree_repo_traverse_reachable_refs (OstreeRepo *self, + guint depth, + GHashTable *reachable, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepoAutoLock) lock = + _ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_SHARED, cancellable, error); + if (!lock) + return FALSE; + + /* Ignoring collections. */ + g_autoptr(GHashTable) all_refs = NULL; /* (element-type utf8 utf8) */ + + if (!ostree_repo_list_refs (self, NULL, &all_refs, + cancellable, error)) + return FALSE; + + GLNX_HASH_TABLE_FOREACH_V (all_refs, const char*, checksum) + { + g_debug ("Finding objects to keep for commit %s", checksum); + if (!ostree_repo_traverse_commit_union (self, checksum, depth, reachable, + cancellable, error)) + return FALSE; + } + + /* Using collections. */ + g_autoptr(GHashTable) all_collection_refs = NULL; /* (element-type OstreeChecksumRef utf8) */ + + if (!ostree_repo_list_collection_refs (self, NULL, &all_collection_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, cancellable, error)) + return FALSE; + + GLNX_HASH_TABLE_FOREACH_V (all_collection_refs, const char*, checksum) + { + g_debug ("Finding objects to keep for commit %s", checksum); + if (!ostree_repo_traverse_commit_union (self, checksum, depth, reachable, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_repo_prune: + * @self: Repo + * @flags: Options controlling prune process + * @depth: Stop traversal after this many iterations (-1 for unlimited) + * @out_objects_total: (out): Number of objects found + * @out_objects_pruned: (out): Number of objects deleted + * @out_pruned_object_size_total: (out): Storage size in bytes of objects deleted + * @cancellable: Cancellable + * @error: Error + * + * Delete content from the repository. By default, this function will + * only delete "orphaned" objects not referred to by any commit. This + * can happen during a local commit operation, when we have written + * content objects but not saved the commit referencing them. + * + * However, if %OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY is provided, instead + * of traversing all commits, only refs will be used. Particularly + * when combined with @depth, this is a convenient way to delete + * history from the repository. + * + * Use the %OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE to just determine + * statistics on objects that would be deleted, without actually + * deleting them. + * + * Locking: exclusive + */ +gboolean +ostree_repo_prune (OstreeRepo *self, + OstreeRepoPruneFlags flags, + gint depth, + gint *out_objects_total, + gint *out_objects_pruned, + guint64 *out_pruned_object_size_total, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepoAutoLock) lock = + _ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error); + if (!lock) + return FALSE; + + g_autoptr(GHashTable) objects = NULL; + gboolean refs_only = flags & OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY; + + g_autoptr(GHashTable) reachable = ostree_repo_traverse_new_reachable (); + + /* This original prune API has fixed logic for traversing refs or all commits + * combined with actually deleting content. The newer backend API just does + * the deletion. + */ + + if (refs_only) + { + if (!ostree_repo_traverse_reachable_refs (self, depth, reachable, cancellable, error)) + return FALSE; + } + + if (!ostree_repo_list_objects (self, OSTREE_REPO_LIST_OBJECTS_ALL | OSTREE_REPO_LIST_OBJECTS_NO_PARENTS, + &objects, cancellable, error)) + return FALSE; + + if (!refs_only) + { + GLNX_HASH_TABLE_FOREACH (objects, GVariant*, serialized_key) + { + const char *checksum; + OstreeObjectType objtype; + + ostree_object_name_deserialize (serialized_key, &checksum, &objtype); + + if (objtype != OSTREE_OBJECT_TYPE_COMMIT) + continue; + + g_debug ("Finding objects to keep for commit %s", checksum); + if (!ostree_repo_traverse_commit_union (self, checksum, depth, reachable, + cancellable, error)) + return FALSE; + } + } + + { OstreeRepoPruneOptions opts = { flags, reachable }; + return repo_prune_internal (self, objects, &opts, + out_objects_total, out_objects_pruned, + out_pruned_object_size_total, cancellable, error); + } +} + +/** + * ostree_repo_prune_from_reachable: + * @self: Repo + * @options: Options controlling prune process + * @out_objects_total: (out): Number of objects found + * @out_objects_pruned: (out): Number of objects deleted + * @out_pruned_object_size_total: (out): Storage size in bytes of objects deleted + * @cancellable: Cancellable + * @error: Error + * + * Delete content from the repository. This function is the "backend" + * half of the higher level ostree_repo_prune(). To use this function, + * you determine the root set yourself, and this function finds all other + * unreferenced objects and deletes them. + * + * Use this API when you want to perform more selective pruning - for example, + * retain all commits from a production branch, but just GC some history from + * your dev branch. + * + * The %OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE flag may be specified to just determine + * statistics on objects that would be deleted, without actually deleting them. + * + * Locking: exclusive + * + * Since: 2017.1 + */ +gboolean +ostree_repo_prune_from_reachable (OstreeRepo *self, + OstreeRepoPruneOptions *options, + gint *out_objects_total, + gint *out_objects_pruned, + guint64 *out_pruned_object_size_total, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepoAutoLock) lock = + _ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error); + if (!lock) + return FALSE; + + g_autoptr(GHashTable) objects = NULL; + + if (!ostree_repo_list_objects (self, OSTREE_REPO_LIST_OBJECTS_ALL | OSTREE_REPO_LIST_OBJECTS_NO_PARENTS, + &objects, cancellable, error)) + return FALSE; + + return repo_prune_internal (self, objects, options, out_objects_total, + out_objects_pruned, out_pruned_object_size_total, + cancellable, error); +} diff --git a/src/libostree/ostree-repo-pull-private.h b/src/libostree/ostree-repo-pull-private.h new file mode 100644 index 0000000..689118b --- /dev/null +++ b/src/libostree/ostree-repo-pull-private.h @@ -0,0 +1,171 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-repo-private.h" +#include "ostree-fetcher-util.h" +#include "ostree-remote-private.h" + +G_BEGIN_DECLS + +typedef enum { + OSTREE_FETCHER_SECURITY_STATE_CA_PINNED, + OSTREE_FETCHER_SECURITY_STATE_TLS, + OSTREE_FETCHER_SECURITY_STATE_INSECURE, +} OstreeFetcherSecurityState; + +typedef struct { + OstreeRepo *repo; + int tmpdir_dfd; + OstreeRepoPullFlags flags; + char *remote_name; + char *remote_refspec_name; + OstreeRepoMode remote_mode; + OstreeFetcher *fetcher; + OstreeFetcherSecurityState fetcher_security_state; + + GPtrArray *meta_mirrorlist; /* List of base URIs for fetching metadata */ + GPtrArray *content_mirrorlist; /* List of base URIs for fetching content */ + OstreeRepo *remote_repo_local; + GPtrArray *localcache_repos; /* Array */ + + GMainContext *main_context; + GCancellable *cancellable; + OstreeAsyncProgress *progress; + + GVariant *extra_headers; + char *append_user_agent; + + gboolean dry_run; + gboolean dry_run_emitted_progress; + gboolean legacy_transaction_resuming; + guint n_network_retries; + enum { + OSTREE_PULL_PHASE_FETCHING_REFS, + OSTREE_PULL_PHASE_FETCHING_OBJECTS + } phase; + gint n_scanned_metadata; + + gboolean gpg_verify; + gboolean gpg_verify_summary; + gboolean require_static_deltas; + gboolean disable_static_deltas; + gboolean has_tombstone_commits; + + GBytes *summary_data; + GBytes *summary_data_sig; + GVariant *summary; + GHashTable *summary_deltas_checksums; + GHashTable *ref_original_commits; /* Maps checksum to commit, used by timestamp checks */ + GHashTable *verified_commits; /* Set of commits that have been verified */ + GHashTable *signapi_verified_commits; /* Map of commits that have been signapi verified */ + GHashTable *ref_keyring_map; /* Maps OstreeCollectionRef to keyring remote name */ + GPtrArray *static_delta_superblocks; + GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */ + GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */ + GHashTable *scanned_metadata; /* Maps object name to itself */ + GHashTable *fetched_detached_metadata; /* Map */ + GHashTable *requested_metadata; /* Maps object name to itself */ + GHashTable *requested_content; /* Maps checksum to itself */ + GHashTable *requested_fallback_content; /* Maps checksum to itself */ + GHashTable *pending_fetch_metadata; /* Map */ + GHashTable *pending_fetch_content; /* Map */ + GHashTable *pending_fetch_delta_superblocks; /* Set */ + GHashTable *pending_fetch_deltaparts; /* Set */ + guint n_outstanding_metadata_fetches; + guint n_outstanding_metadata_write_requests; + guint n_outstanding_content_fetches; + guint n_outstanding_content_write_requests; + guint n_outstanding_deltapart_fetches; + guint n_outstanding_deltapart_write_requests; + guint n_total_deltaparts; + guint n_total_delta_fallbacks; + guint64 fetched_deltapart_size; /* How much of the delta we have now */ + guint64 total_deltapart_size; + guint64 total_deltapart_usize; + gint n_requested_metadata; + gint n_requested_content; + guint n_fetched_deltaparts; + guint n_fetched_deltapart_fallbacks; + guint n_fetched_metadata; + guint n_fetched_content; + /* Objects imported via hardlink/reflink/copying or --localcache-repo*/ + guint n_imported_metadata; + guint n_imported_content; + + gboolean timestamp_check; /* Verify commit timestamps */ + char *timestamp_check_from_rev; + int maxdepth; + guint64 max_metadata_size; + guint64 start_time; + + gboolean is_mirror; + gboolean trusted_http_direct; + gboolean is_commit_only; + OstreeRepoImportFlags importflags; + + GPtrArray *signapi_commit_verifiers; + GPtrArray *signapi_summary_verifiers; + + GPtrArray *dirs; + + gboolean have_previous_bytes; + guint64 previous_bytes_sec; + guint64 previous_total_downloaded; + + GError *cached_async_error; + GError **async_error; + gboolean caught_error; + + GQueue scan_object_queue; + GSource *idle_src; +} OtPullData; + +gboolean +_signapi_init_for_remote (OstreeRepo *repo, + const char *remote_name, + GPtrArray **out_commit_verifiers, + GPtrArray **out_summary_verifiers, + GError **error); +gboolean +_sign_verify_for_remote (GPtrArray *signers, + GBytes *signed_data, + GVariant *metadata, + char **out_success_message, + GError **error); + +gboolean +_verify_unwritten_commit (OtPullData *pull_data, + const char *checksum, + GVariant *commit, + GVariant *detached_metadata, + const OstreeCollectionRef *ref, + GCancellable *cancellable, + GError **error); + +gboolean +_process_gpg_verify_result (OtPullData *pull_data, + const char *checksum, + OstreeGpgVerifyResult *result, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-pull-verify.c b/src/libostree/ostree-repo-pull-verify.c new file mode 100644 index 0000000..fa170f9 --- /dev/null +++ b/src/libostree/ostree-repo-pull-verify.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libglnx.h" +#include "ostree.h" +#include "otutil.h" +#include "ostree-repo-pull-private.h" +#include "ostree-repo-private.h" + +#include "ostree-core-private.h" +#include "ostree-repo-static-delta-private.h" +#include "ostree-metalink.h" +#include "ostree-fetcher-util.h" +#include "ostree-remote-private.h" +#include "ot-fs-utils.h" + +#include +#include +#ifdef HAVE_LIBSYSTEMD +#include +#endif + +#include "ostree-sign.h" + +static gboolean +get_signapi_remote_option (OstreeRepo *repo, + OstreeSign *sign, + const char *remote_name, + const char *keysuffix, + char **out_value, + GError **error) +{ + g_autofree char *key = g_strdup_printf ("verification-%s-%s", ostree_sign_get_name (sign), keysuffix); + return ostree_repo_get_remote_option (repo, remote_name, key, NULL, out_value, error); +} + +/* _signapi_load_public_keys: + * + * Load public keys according remote's configuration: + * inlined key passed via config option `verification--key` or + * file name with public keys via `verification--file` option. + * + * If both options are set then load all all public keys + * both from file and inlined in config. + * + * Returns: %FALSE if any source is configured but nothing has been loaded. + * Returns: %TRUE if no configuration or any key loaded. + * */ +static gboolean +_signapi_load_public_keys (OstreeSign *sign, + OstreeRepo *repo, + const gchar *remote_name, + gboolean required, + GError **error) +{ + g_autofree gchar *pk_ascii = NULL; + g_autofree gchar *pk_file = NULL; + gboolean loaded_from_file = TRUE; + gboolean loaded_inlined = TRUE; + + if (!get_signapi_remote_option (repo, sign, remote_name, "file", &pk_file, error)) + return FALSE; + if (!get_signapi_remote_option (repo, sign, remote_name, "key", &pk_ascii, error)) + return FALSE; + + /* return TRUE if there is no configuration for remote */ + if ((pk_file == NULL) &&(pk_ascii == NULL)) + { + /* It is expected what remote may have verification file as + * a part of configuration. Hence there is not a lot of sense + * for automatic resolve of per-remote keystore file as it + * used in find_keyring () for GPG. + * If it is needed to add the similar mechanism, it is preferable + * to pass the path to ostree_sign_load_pk () via GVariant options + * and call it here for loading with method and file structure + * specific for signature type. + */ + if (required) + return glnx_throw (error, "No keys found for required signapi type %s", ostree_sign_get_name (sign)); + return TRUE; + } + + if (pk_file != NULL) + { + g_autoptr (GError) local_error = NULL; + g_autoptr (GVariantBuilder) builder = NULL; + g_autoptr (GVariant) options = NULL; + + builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (builder, "{sv}", "filename", g_variant_new_string (pk_file)); + options = g_variant_builder_end (builder); + + if (ostree_sign_load_pk (sign, options, &local_error)) + loaded_from_file = TRUE; + else + { + return glnx_throw (error, "Failed loading '%s' keys from '%s", + ostree_sign_get_name (sign), pk_file); + } + } + + if (pk_ascii != NULL) + { + g_autoptr (GError) local_error = NULL; + g_autoptr (GVariant) pk = g_variant_new_string(pk_ascii); + + /* Add inlined public key */ + if (loaded_from_file) + loaded_inlined = ostree_sign_add_pk (sign, pk, &local_error); + else + loaded_inlined = ostree_sign_set_pk (sign, pk, &local_error); + + if (!loaded_inlined) + { + return glnx_throw (error, "Failed loading '%s' keys from inline `verification-key`", + ostree_sign_get_name (sign)); + } + } + + /* Return true if able to load from any source */ + if (!(loaded_from_file || loaded_inlined)) + return glnx_throw (error, "No keys found"); + + return TRUE; +} + +static gboolean +string_is_gkeyfile_truthy (const char *value, + gboolean *out_truth) +{ + /* See https://gitlab.gnome.org/GNOME/glib/-/blob/20fb5bf868added5aec53c013ae85ec78ba2eedc/glib/gkeyfile.c#L4528 */ + if (g_str_equal (value, "true") || g_str_equal (value, "1")) + { + *out_truth = TRUE; + return TRUE; + } + else if (g_str_equal (value, "false") || g_str_equal (value, "0")) + { + *out_truth = FALSE; + return TRUE; + } + return FALSE; +} + +static gboolean +verifiers_from_config (OstreeRepo *repo, + const char *remote_name, + const char *key, + GPtrArray **out_verifiers, + GError **error) +{ + g_autoptr(GPtrArray) verifiers = NULL; + + g_autofree char *raw_value = NULL; + if (!ostree_repo_get_remote_option (repo, remote_name, + key, NULL, + &raw_value, error)) + return FALSE; + if (raw_value == NULL || g_str_equal (raw_value, "")) + { + *out_verifiers = NULL; + return TRUE; + } + gboolean sign_verify_bool = FALSE; + /* Is the value "truthy" according to GKeyFile's rules? If so, + * then we take this to be "accept signatures from any compiled + * type that happens to have keys configured". + */ + if (string_is_gkeyfile_truthy (raw_value, &sign_verify_bool)) + { + if (sign_verify_bool) + { + verifiers = ostree_sign_get_all (); + for (guint i = 0; i < verifiers->len; i++) + { + OstreeSign *sign = verifiers->pdata[i]; + /* Try to load public key(s) according remote's configuration; + * this one is optional. + */ + if (!_signapi_load_public_keys (sign, repo, remote_name, FALSE, error)) + return FALSE; + } + } + } + else + { + /* If the value isn't "truthy", then it must be an explicit list */ + g_auto(GStrv) sign_types = NULL; + if (!ostree_repo_get_remote_list_option (repo, remote_name, + key, &sign_types, + error)) + return FALSE; + verifiers = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + for (char **iter = sign_types; iter && *iter; iter++) + { + const char *sign_type = *iter; + OstreeSign *verifier = ostree_sign_get_by_name (sign_type, error); + if (!verifier) + return FALSE; + if (!_signapi_load_public_keys (verifier, repo, remote_name, TRUE, error)) + return FALSE; + g_ptr_array_add (verifiers, verifier); + } + g_assert_cmpuint (verifiers->len, >=, 1); + } + + *out_verifiers = g_steal_pointer (&verifiers); + return TRUE; +} + +/* Create a new array of OstreeSign objects and load the public + * keys as described by the remote configuration. If the + * remote does not have signing verification enabled, then + * the resulting verifier list will be NULL. + */ +gboolean +_signapi_init_for_remote (OstreeRepo *repo, + const char *remote_name, + GPtrArray **out_commit_verifiers, + GPtrArray **out_summary_verifiers, + GError **error) +{ + g_autoptr(GPtrArray) commit_verifiers = NULL; + g_autoptr(GPtrArray) summary_verifiers = NULL; + + if (!verifiers_from_config (repo, remote_name, "sign-verify", &commit_verifiers, error)) + return FALSE; + if (!verifiers_from_config (repo, remote_name, "sign-verify-summary", &summary_verifiers, error)) + return FALSE; + + ot_transfer_out_value (out_commit_verifiers, &commit_verifiers); + ot_transfer_out_value (out_summary_verifiers, &summary_verifiers); + return TRUE; +} + +/* Iterate over the configured verifiers, and require the commit is signed + * by at least one. + */ +gboolean +_sign_verify_for_remote (GPtrArray *verifiers, + GBytes *signed_data, + GVariant *metadata, + char **out_success_message, + GError **error) +{ + guint n_invalid_signatures = 0; + g_autoptr (GError) last_sig_error = NULL; + gboolean found_sig = FALSE; + + g_assert (out_success_message == NULL || *out_success_message == NULL); + + g_assert_cmpuint (verifiers->len, >=, 1); + for (guint i = 0; i < verifiers->len; i++) + { + OstreeSign *sign = verifiers->pdata[i]; + const gchar *signature_key = ostree_sign_metadata_key (sign); + GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format (sign); + g_autoptr (GVariant) signatures = + g_variant_lookup_value (metadata, signature_key, signature_format); + + /* If not found signatures for requested signature subsystem */ + if (!signatures) + continue; + + found_sig = TRUE; + + g_autofree char *success_message = NULL; + /* Return true if any signature fit to pre-loaded public keys. + * If no keys configured -- then system configuration will be used */ + if (!ostree_sign_data_verify (sign, + signed_data, + signatures, + &success_message, + last_sig_error ? NULL : &last_sig_error)) + { + n_invalid_signatures++; + continue; + } + /* Accept the first valid signature */ + if (out_success_message) + *out_success_message = g_steal_pointer (&success_message); + return TRUE; + } + + if (!found_sig) + return glnx_throw (error, "No signatures found"); + + g_assert (last_sig_error); + g_propagate_error (error, g_steal_pointer (&last_sig_error)); + if (n_invalid_signatures > 1) + glnx_prefix_error (error, "(%d other invalid signatures)", n_invalid_signatures-1); + return FALSE; +} + + +#ifndef OSTREE_DISABLE_GPGME +gboolean +_process_gpg_verify_result (OtPullData *pull_data, + const char *checksum, + OstreeGpgVerifyResult *result, + GError **error) +{ + const char *error_prefix = glnx_strjoina ("Commit ", checksum); + GLNX_AUTO_PREFIX_ERROR(error_prefix, error); + if (result == NULL) + return FALSE; + + /* Allow callers to output the results immediately. */ + g_signal_emit_by_name (pull_data->repo, + "gpg-verify-result", + checksum, result); + + if (!ostree_gpg_verify_result_require_valid_signature (result, error)) + return FALSE; + + + /* We now check both *before* writing the commit, and after. Because the + * behavior used to be only verifiying after writing, we need to handle + * the case of "written but not verified". But we also don't want to check + * twice, as that'd result in duplicate signals. + */ + g_hash_table_add (pull_data->verified_commits, g_strdup (checksum)); + + return TRUE; +} +#endif /* OSTREE_DISABLE_GPGME */ + +gboolean +_verify_unwritten_commit (OtPullData *pull_data, + const char *checksum, + GVariant *commit, + GVariant *detached_metadata, + const OstreeCollectionRef *ref, + GCancellable *cancellable, + GError **error) +{ + /* Shouldn't happen, but see comment in process_gpg_verify_result() */ + if ((!pull_data->gpg_verify || g_hash_table_contains (pull_data->verified_commits, checksum)) + && (!pull_data->signapi_commit_verifiers || g_hash_table_contains (pull_data->signapi_verified_commits, checksum))) + return TRUE; + + g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit); + +#ifndef OSTREE_DISABLE_GPGME + if (pull_data->gpg_verify) + { + const char *keyring_remote = NULL; + + if (ref != NULL) + keyring_remote = g_hash_table_lookup (pull_data->ref_keyring_map, ref); + if (keyring_remote == NULL) + keyring_remote = pull_data->remote_name; + + g_autoptr(OstreeGpgVerifyResult) result = + _ostree_repo_gpg_verify_with_metadata (pull_data->repo, signed_data, + detached_metadata, + keyring_remote, + NULL, NULL, cancellable, error); + if (!_process_gpg_verify_result (pull_data, checksum, result, error)) + return FALSE; + } +#endif /* OSTREE_DISABLE_GPGME */ + + if (pull_data->signapi_commit_verifiers) + { + /* Nothing to check if detached metadata is absent */ + if (detached_metadata == NULL) + return glnx_throw (error, "Can't verify commit without detached metadata"); + + g_autofree char *success_message = NULL; + if (!_sign_verify_for_remote (pull_data->signapi_commit_verifiers, signed_data, detached_metadata, &success_message, error)) + return glnx_prefix_error (error, "Can't verify commit"); + + /* Mark the commit as verified to avoid double verification + * see process_verify_result () for rationale */ + g_hash_table_insert (pull_data->signapi_verified_commits, g_strdup (checksum), g_steal_pointer (&success_message)); + } + + return TRUE; +} diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c new file mode 100644 index 0000000..5fdbeab --- /dev/null +++ b/src/libostree/ostree-repo-pull.c @@ -0,0 +1,6275 @@ +/* + * Copyright (C) 2011,2012,2013 Colin Walters + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Colin Walters + * - Philip Withnall + */ + +#include "config.h" + +#include "libglnx.h" +#include "ostree.h" +#include "otutil.h" +#include "ostree-repo-pull-private.h" + +#ifdef HAVE_LIBCURL_OR_LIBSOUP + +#include "ostree-core-private.h" +#include "ostree-repo-static-delta-private.h" +#include "ostree-metalink.h" + +#include "ostree-repo-finder.h" +#include "ostree-repo-finder-config.h" +#include "ostree-repo-finder-mount.h" +#ifdef HAVE_AVAHI +#include "ostree-repo-finder-avahi.h" +#endif /* HAVE_AVAHI */ + +#include +#include +#ifdef HAVE_LIBSYSTEMD +#include +#endif + +#define OSTREE_MESSAGE_FETCH_COMPLETE_ID SD_ID128_MAKE(75,ba,3d,eb,0a,f0,41,a9,a4,62,72,ff,85,d9,e7,3e) + +#define OSTREE_REPO_PULL_CONTENT_PRIORITY (OSTREE_FETCHER_DEFAULT_PRIORITY) +#define OSTREE_REPO_PULL_METADATA_PRIORITY (OSTREE_REPO_PULL_CONTENT_PRIORITY - 100) + +/* Arbitrarily chosen number of retries for all download operations when they + * receive a transient network error (such as a socket timeout) — see + * _ostree_fetcher_should_retry_request(). This is the default value for the + * `n-network-retries` pull option. */ +#define DEFAULT_N_NETWORK_RETRIES 5 + +typedef struct { + OtPullData *pull_data; + GVariant *object; + char *path; + gboolean is_detached_meta; + + /* Only relevant when is_detached_meta is TRUE. Controls + * whether to fetch the primary object after fetching its + * detached metadata (no need if it's already stored). */ + gboolean object_is_stored; + + OstreeCollectionRef *requested_ref; /* (nullable) */ + guint n_retries_remaining; +} FetchObjectData; + +typedef struct { + OtPullData *pull_data; + GVariant *objects; + char *expected_checksum; + char *from_revision; + char *to_revision; + guint i; + guint64 size; + guint n_retries_remaining; +} FetchStaticDeltaData; + +typedef struct { + guchar csum[OSTREE_SHA256_DIGEST_LEN]; + char *path; + OstreeObjectType objtype; + guint recursion_depth; /* NB: not used anymore, though might be nice to print */ + OstreeCollectionRef *requested_ref; /* (nullable) */ +} ScanObjectQueueData; + +typedef struct { + OtPullData *pull_data; + char *from_revision; + char *to_revision; + OstreeCollectionRef *requested_ref; /* (nullable) */ + guint n_retries_remaining; +} FetchDeltaSuperData; + +static void +variant_or_null_unref (gpointer data) +{ + if (data) + g_variant_unref (data); +} + +static void start_fetch (OtPullData *pull_data, FetchObjectData *fetch); +static void start_fetch_deltapart (OtPullData *pull_data, + FetchStaticDeltaData *fetch); +static void start_fetch_delta_superblock (OtPullData *pull_data, + FetchDeltaSuperData *fetch_data); +static gboolean fetcher_queue_is_full (OtPullData *pull_data); +static void queue_scan_one_metadata_object (OtPullData *pull_data, + const char *csum, + OstreeObjectType objtype, + const char *path, + guint recursion_depth, + const OstreeCollectionRef *ref); + +static void queue_scan_one_metadata_object_s (OtPullData *pull_data, + ScanObjectQueueData *scan_data); +static void queue_scan_one_metadata_object_c (OtPullData *pull_data, + const guchar *csum, + OstreeObjectType objtype, + const char *path, + guint recursion_depth, + const OstreeCollectionRef *ref); + +static void enqueue_one_object_request_s (OtPullData *pull_data, + FetchObjectData *fetch_data); +static void enqueue_one_static_delta_superblock_request_s (OtPullData *pull_data, + FetchDeltaSuperData *fetch_data); +static void enqueue_one_static_delta_part_request_s (OtPullData *pull_data, + FetchStaticDeltaData *fetch_data); + +static gboolean scan_one_metadata_object (OtPullData *pull_data, + const char *checksum, + OstreeObjectType objtype, + const char *path, + guint recursion_depth, + const OstreeCollectionRef *ref, + GCancellable *cancellable, + GError **error); +static void scan_object_queue_data_free (ScanObjectQueueData *scan_data); + +static gboolean +update_progress (gpointer user_data) +{ + OtPullData *pull_data; + guint outstanding_writes; + guint outstanding_fetches; + guint64 bytes_transferred; + guint fetched; + guint requested; + guint n_scanned_metadata; + guint64 start_time; + + pull_data = user_data; + + if (! pull_data->progress) + return FALSE; + + /* In dry run, we only emit progress once metadata is done */ + if (pull_data->dry_run && pull_data->n_outstanding_metadata_fetches > 0) + return TRUE; + + outstanding_writes = pull_data->n_outstanding_content_write_requests + + pull_data->n_outstanding_metadata_write_requests + + pull_data->n_outstanding_deltapart_write_requests; + outstanding_fetches = pull_data->n_outstanding_content_fetches + + pull_data->n_outstanding_metadata_fetches + + pull_data->n_outstanding_deltapart_fetches; + bytes_transferred = _ostree_fetcher_bytes_transferred (pull_data->fetcher); + fetched = pull_data->n_fetched_metadata + pull_data->n_fetched_content; + requested = pull_data->n_requested_metadata + pull_data->n_requested_content; + n_scanned_metadata = pull_data->n_scanned_metadata; + start_time = pull_data->start_time; + + ostree_async_progress_set (pull_data->progress, + "outstanding-fetches", "u", outstanding_fetches, + "outstanding-writes", "u", outstanding_writes, + "fetched", "u", fetched, + "requested", "u", requested, + "scanning", "u", g_queue_is_empty (&pull_data->scan_object_queue) ? 0 : 1, + "caught-error", "b", pull_data->caught_error, + "scanned-metadata", "u", n_scanned_metadata, + "bytes-transferred", "t", bytes_transferred, + "start-time", "t", start_time, + /* We use these status keys even though we now also + * use these values for filesystem-local pulls. + */ + "metadata-fetched-localcache", "u", pull_data->n_imported_metadata, + "content-fetched-localcache", "u", pull_data->n_imported_content, + /* Deltas */ + "fetched-delta-parts", + "u", pull_data->n_fetched_deltaparts, + "total-delta-parts", + "u", pull_data->n_total_deltaparts, + "fetched-delta-fallbacks", + "u", pull_data->n_fetched_deltapart_fallbacks, + "total-delta-fallbacks", + "u", pull_data->n_total_delta_fallbacks, + "fetched-delta-part-size", + "t", pull_data->fetched_deltapart_size, + "total-delta-part-size", + "t", pull_data->total_deltapart_size, + "total-delta-part-usize", + "t", pull_data->total_deltapart_usize, + "total-delta-superblocks", + "u", pull_data->static_delta_superblocks->len, + /* We fetch metadata before content. These allow us to report metadata fetch progress specifically. */ + "outstanding-metadata-fetches", "u", pull_data->n_outstanding_metadata_fetches, + "metadata-fetched", "u", pull_data->n_fetched_metadata, + /* Overall status. */ + "status", "s", "", + NULL); + + if (pull_data->dry_run) + pull_data->dry_run_emitted_progress = TRUE; + + return TRUE; +} + +/* The core logic function for whether we should continue the main loop */ +static gboolean +pull_termination_condition (OtPullData *pull_data) +{ + gboolean current_fetch_idle = (pull_data->n_outstanding_metadata_fetches == 0 && + pull_data->n_outstanding_content_fetches == 0 && + pull_data->n_outstanding_deltapart_fetches == 0); + gboolean current_write_idle = (pull_data->n_outstanding_metadata_write_requests == 0 && + pull_data->n_outstanding_content_write_requests == 0 && + pull_data->n_outstanding_deltapart_write_requests == 0 ); + gboolean current_scan_idle = g_queue_is_empty (&pull_data->scan_object_queue); + gboolean current_idle = current_fetch_idle && current_write_idle && current_scan_idle; + + /* we only enter the main loop when we're fetching objects */ + g_assert (pull_data->phase == OSTREE_PULL_PHASE_FETCHING_OBJECTS); + + if (pull_data->dry_run) + return pull_data->dry_run_emitted_progress; + + if (current_idle) + g_debug ("pull: idle, exiting mainloop"); + + return current_idle; +} + +/* Most async operations finish by calling this function; it will consume + * @errorp if set, update statistics, and initiate processing of any further + * requests as appropriate. + */ +static void +check_outstanding_requests_handle_error (OtPullData *pull_data, + GError **errorp) +{ + g_assert (errorp); + + GError *error = *errorp; + if (error) + { + g_debug ("Request caught error: %s", error->message); + + if (!pull_data->caught_error) + { + pull_data->caught_error = TRUE; + g_propagate_error (pull_data->async_error, g_steal_pointer (errorp)); + } + else + { + g_clear_error (errorp); + } + } + + /* If we're in error state, we wait for any pending operations to complete, + * but ensure that all no further operations are queued. + */ + if (pull_data->caught_error) + { + g_queue_foreach (&pull_data->scan_object_queue, (GFunc) scan_object_queue_data_free, NULL); + g_queue_clear (&pull_data->scan_object_queue); + g_hash_table_remove_all (pull_data->pending_fetch_metadata); + g_hash_table_remove_all (pull_data->pending_fetch_delta_superblocks); + g_hash_table_remove_all (pull_data->pending_fetch_deltaparts); + g_hash_table_remove_all (pull_data->pending_fetch_content); + } + else + { + GHashTableIter hiter; + gpointer key, value; + + /* We may have just completed an async fetch operation. Now we look at + * possibly enqueuing more requests. The goal of queuing is to both avoid + * overloading the fetcher backend with HTTP requests, but also to + * prioritize metadata fetches over content, so we have accurate + * reporting. Hence here, we process metadata fetches first. + */ + + /* Try filling the queue with metadata we need to fetch */ + g_hash_table_iter_init (&hiter, pull_data->pending_fetch_metadata); + while (!fetcher_queue_is_full (pull_data) && + g_hash_table_iter_next (&hiter, &key, &value)) + { + GVariant *objname = key; + FetchObjectData *fetch = value; + + /* Steal both key and value */ + g_hash_table_iter_steal (&hiter); + + /* This takes ownership of the value */ + start_fetch (pull_data, fetch); + /* And unref the key */ + g_variant_unref (objname); + } + + /* Next, process delta superblock requests */ + g_hash_table_iter_init (&hiter, pull_data->pending_fetch_delta_superblocks); + while (!fetcher_queue_is_full (pull_data) && + g_hash_table_iter_next (&hiter, &key, &value)) + { + FetchDeltaSuperData *fetch = key; + g_hash_table_iter_steal (&hiter); + start_fetch_delta_superblock (pull_data, g_steal_pointer (&fetch)); + } + + /* Now, process deltapart requests */ + g_hash_table_iter_init (&hiter, pull_data->pending_fetch_deltaparts); + while (!fetcher_queue_is_full (pull_data) && + g_hash_table_iter_next (&hiter, &key, &value)) + { + FetchStaticDeltaData *fetch = key; + g_hash_table_iter_steal (&hiter); + /* Takes ownership */ + start_fetch_deltapart (pull_data, fetch); + } + + /* Next, fill the queue with content */ + g_hash_table_iter_init (&hiter, pull_data->pending_fetch_content); + while (!fetcher_queue_is_full (pull_data) && + g_hash_table_iter_next (&hiter, &key, &value)) + { + char *checksum = key; + FetchObjectData *fetch = value; + + /* Steal both key and value */ + g_hash_table_iter_steal (&hiter); + + /* This takes ownership of the value */ + start_fetch (pull_data, fetch); + /* And unref the key */ + g_free (checksum); + } + + } +} + +/* We have a total-request limit, as well has a hardcoded max of 2 for delta + * parts. The logic for the delta one is that processing them is expensive, and + * doing multiple simultaneously could risk space/memory on smaller devices. We + * also throttle on outstanding writes in case fetches are faster. + */ +static gboolean +fetcher_queue_is_full (OtPullData *pull_data) +{ + const gboolean fetch_full = + ((pull_data->n_outstanding_metadata_fetches + + pull_data->n_outstanding_content_fetches + + pull_data->n_outstanding_deltapart_fetches) == + _OSTREE_MAX_OUTSTANDING_FETCHER_REQUESTS); + const gboolean deltas_full = + (pull_data->n_outstanding_deltapart_fetches == + _OSTREE_MAX_OUTSTANDING_DELTAPART_REQUESTS); + const gboolean writes_full = + ((pull_data->n_outstanding_metadata_write_requests + + pull_data->n_outstanding_content_write_requests + + pull_data->n_outstanding_deltapart_write_requests) >= + _OSTREE_MAX_OUTSTANDING_WRITE_REQUESTS); + return fetch_full || deltas_full || writes_full; +} + +static void +scan_object_queue_data_free (ScanObjectQueueData *scan_data) +{ + g_free (scan_data->path); + if (scan_data->requested_ref != NULL) + ostree_collection_ref_free (scan_data->requested_ref); + g_free (scan_data); +} + +/* Called out of the main loop to process the "scan object queue", which is a + * queue of metadata objects (commits and dirtree, but not dirmeta) to parse to + * look for further objects. Basically wraps execution of + * `scan_one_metadata_object()`. + */ +static gboolean +idle_worker (gpointer user_data) +{ + OtPullData *pull_data = user_data; + ScanObjectQueueData *scan_data; + g_autoptr(GError) error = NULL; + + scan_data = g_queue_pop_head (&pull_data->scan_object_queue); + if (!scan_data) + { + g_clear_pointer (&pull_data->idle_src, (GDestroyNotify) g_source_destroy); + return G_SOURCE_REMOVE; + } + + char checksum[OSTREE_SHA256_STRING_LEN+1]; + ostree_checksum_inplace_from_bytes (scan_data->csum, checksum); + scan_one_metadata_object (pull_data, checksum, scan_data->objtype, + scan_data->path, scan_data->recursion_depth, + scan_data->requested_ref, pull_data->cancellable, &error); + + /* No need to retry scan tasks, since they’re local. */ + check_outstanding_requests_handle_error (pull_data, &error); + scan_object_queue_data_free (scan_data); + + return G_SOURCE_CONTINUE; +} + +static void +ensure_idle_queued (OtPullData *pull_data) +{ + GSource *idle_src; + + if (pull_data->idle_src) + return; + + idle_src = g_idle_source_new (); + g_source_set_callback (idle_src, idle_worker, pull_data, NULL); + g_source_attach (idle_src, pull_data->main_context); + g_source_unref (idle_src); + pull_data->idle_src = idle_src; +} + +typedef struct { + OtPullData *pull_data; + GInputStream *result_stream; +} OstreeFetchUriSyncData; + +static gboolean +fetch_mirrored_uri_contents_utf8_sync (OstreeFetcher *fetcher, + GPtrArray *mirrorlist, + const char *filename, + guint n_network_retries, + char **out_contents, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GBytes) bytes = NULL; + if (!_ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist, + filename, OSTREE_FETCHER_REQUEST_NUL_TERMINATION, + n_network_retries, + &bytes, + OSTREE_MAX_METADATA_SIZE, + cancellable, error)) + return FALSE; + + gsize len; + g_autofree char *ret_contents = g_bytes_unref_to_data (g_steal_pointer (&bytes), &len); + + if (!g_utf8_validate (ret_contents, -1, NULL)) + return glnx_throw (error, "Invalid UTF-8"); + + ot_transfer_out_value (out_contents, &ret_contents); + return TRUE; +} + +static gboolean +fetch_uri_contents_utf8_sync (OstreeFetcher *fetcher, + OstreeFetcherURI *uri, + guint n_network_retries, + char **out_contents, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GPtrArray) mirrorlist = g_ptr_array_new (); + g_ptr_array_add (mirrorlist, uri); /* no transfer */ + return fetch_mirrored_uri_contents_utf8_sync (fetcher, mirrorlist, + NULL, n_network_retries, + out_contents, + cancellable, error); +} + +static void +enqueue_one_object_request (OtPullData *pull_data, + const char *checksum, + OstreeObjectType objtype, + const char *path, + gboolean is_detached_meta, + gboolean object_is_stored, + const OstreeCollectionRef *ref); + +static gboolean +matches_pull_dir (const char *current_file, + const char *pull_dir, + gboolean current_file_is_dir) +{ + const char *rest; + + if (g_str_has_prefix (pull_dir, current_file)) + { + rest = pull_dir + strlen (current_file); + if (*rest == 0) + { + /* The current file is exactly the same as the specified + pull dir. This matches always, even if the file is not a + directory. */ + return TRUE; + } + + if (*rest == '/') + { + /* The current file is a directory-prefix of the pull_dir. + Match only if this is supposed to be a directory */ + return current_file_is_dir; + } + + /* Matched a non-directory prefix such as /foo being a prefix of /fooo, + no match */ + return FALSE; + } + + if (g_str_has_prefix (current_file, pull_dir)) + { + rest = current_file + strlen (pull_dir); + /* Only match if the prefix match matched the entire directory + component */ + return *rest == '/'; + } + + return FALSE; +} + + +static gboolean +pull_matches_subdir (OtPullData *pull_data, + const char *path, + const char *basename, + gboolean basename_is_dir) +{ + if (pull_data->dirs == NULL) + return TRUE; + + g_autofree char *file = g_strconcat (path, basename, NULL); + + for (guint i = 0; i < pull_data->dirs->len; i++) + { + const char *pull_dir = g_ptr_array_index (pull_data->dirs, i); + if (matches_pull_dir (file, pull_dir, basename_is_dir)) + return TRUE; + } + + return FALSE; +} + +typedef struct { + OtPullData *pull_data; + OstreeRepo *src_repo; + char checksum[OSTREE_SHA256_STRING_LEN+1]; +} ImportLocalAsyncData; + +/* Asynchronously import a single content object. @src_repo is either + * pull_data->remote_repo_local or one of pull_data->localcache_repos. + */ +static void +async_import_in_thread (GTask *task, + gpointer source, + gpointer task_data, + GCancellable *cancellable) +{ + ImportLocalAsyncData *iataskdata = task_data; + OtPullData *pull_data = iataskdata->pull_data; + g_autoptr(GError) local_error = NULL; + /* pull_data->importflags was set up in the pull option processing */ + if (!_ostree_repo_import_object (pull_data->repo, iataskdata->src_repo, + OSTREE_OBJECT_TYPE_FILE, iataskdata->checksum, + pull_data->importflags, cancellable, &local_error)) + g_task_return_error (task, g_steal_pointer (&local_error)); + else + g_task_return_boolean (task, TRUE); +} + +/* Start an async import of a single object; currently used for content objects. + * @src_repo is from pull_data->remote_repo_local or + * pull_data->localcache_repos. + * + * One important special case here is handling the + * OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES flag. + */ +static void +async_import_one_local_content_object (OtPullData *pull_data, + OstreeRepo *src_repo, + const char *checksum, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + ImportLocalAsyncData *iataskdata = g_new0 (ImportLocalAsyncData, 1); + iataskdata->pull_data = pull_data; + iataskdata->src_repo = src_repo; + memcpy (iataskdata->checksum, checksum, OSTREE_SHA256_STRING_LEN); + g_autoptr(GTask) task = g_task_new (pull_data->repo, cancellable, callback, user_data); + g_task_set_source_tag (task, async_import_one_local_content_object); + g_task_set_task_data (task, iataskdata, g_free); + pull_data->n_outstanding_content_write_requests++; + g_task_run_in_thread (task, async_import_in_thread); +} + +static gboolean +async_import_one_local_content_object_finish (OtPullData *pull_data, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, pull_data->repo), FALSE); + return g_task_propagate_boolean ((GTask*)result, error); +} + +static void +on_local_object_imported (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + OtPullData *pull_data = user_data; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + + if (!async_import_one_local_content_object_finish (pull_data, result, error)) + goto out; + + out: + pull_data->n_imported_content++; + g_assert_cmpint (pull_data->n_outstanding_content_write_requests, >, 0); + pull_data->n_outstanding_content_write_requests--; + /* No retries for local reads. */ + check_outstanding_requests_handle_error (pull_data, &local_error); +} + +static gboolean +scan_dirtree_object (OtPullData *pull_data, + const char *checksum, + const char *path, + int recursion_depth, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) tree = NULL; + if (!ostree_repo_load_variant (pull_data->repo, OSTREE_OBJECT_TYPE_DIR_TREE, checksum, + &tree, error)) + return FALSE; + + /* PARSE OSTREE_SERIALIZED_TREE_VARIANT */ + g_autoptr(GVariant) files_variant = g_variant_get_child_value (tree, 0); + const guint n = g_variant_n_children (files_variant); + for (guint i = 0; i < n; i++) + { + const char *filename; + gboolean file_is_stored; + g_autoptr(GVariant) csum = NULL; + g_autofree char *file_checksum = NULL; + + g_variant_get_child (files_variant, i, "(&s@ay)", &filename, &csum); + + /* Note this is now obsoleted by the _ostree_validate_structureof_metadata() + * but I'm keeping this since: + * 1) It's cheap + * 2) We want to continue to do validation for objects written to disk + * before libostree's validation was strengthened. + */ + if (!ot_util_filename_validate (filename, error)) + return FALSE; + + /* Skip files if we're traversing a request only directory, unless it exactly + * matches the path */ + if (!pull_matches_subdir (pull_data, path, filename, FALSE)) + continue; + + file_checksum = ostree_checksum_from_bytes_v (csum); + + if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_FILE, file_checksum, + &file_is_stored, cancellable, error)) + return FALSE; + + /* If we already have this object, move on to the next */ + if (file_is_stored) + continue; + + /* Already have a request pending? If so, move on to the next */ + if (g_hash_table_lookup (pull_data->requested_content, file_checksum)) + continue; + + /* Is this a local repo? */ + if (pull_data->remote_repo_local) + { + async_import_one_local_content_object (pull_data, pull_data->remote_repo_local, + file_checksum, cancellable, + on_local_object_imported, + pull_data); + g_hash_table_add (pull_data->requested_content, g_steal_pointer (&file_checksum)); + /* Note early loop continue */ + continue; + } + + /* We're doing HTTP, but see if we have the object in a local cache first */ + gboolean did_import_from_cache_repo = FALSE; + if (pull_data->localcache_repos) + { + for (guint j = 0; j < pull_data->localcache_repos->len; j++) + { + OstreeRepo *localcache_repo = pull_data->localcache_repos->pdata[j]; + gboolean localcache_repo_has_obj; + + if (!ostree_repo_has_object (localcache_repo, OSTREE_OBJECT_TYPE_FILE, file_checksum, + &localcache_repo_has_obj, cancellable, error)) + return FALSE; + if (!localcache_repo_has_obj) + continue; + async_import_one_local_content_object (pull_data, localcache_repo, file_checksum, cancellable, + on_local_object_imported, pull_data); + g_hash_table_add (pull_data->requested_content, g_steal_pointer (&file_checksum)); + did_import_from_cache_repo = TRUE; + break; + } + } + if (did_import_from_cache_repo) + continue; /* Note early continue */ + + /* Not available locally, queue a HTTP request */ + g_hash_table_add (pull_data->requested_content, file_checksum); + enqueue_one_object_request (pull_data, file_checksum, OSTREE_OBJECT_TYPE_FILE, path, FALSE, FALSE, NULL); + file_checksum = NULL; /* Transfer ownership */ + } + + g_autoptr(GVariant) dirs_variant = g_variant_get_child_value (tree, 1); + const guint m = g_variant_n_children (dirs_variant); + for (guint i = 0; i < m; i++) + { + const char *dirname = NULL; + g_autoptr(GVariant) tree_csum = NULL; + g_autoptr(GVariant) meta_csum = NULL; + g_variant_get_child (dirs_variant, i, "(&s@ay@ay)", + &dirname, &tree_csum, &meta_csum); + + /* See comment above for files */ + if (!ot_util_filename_validate (dirname, error)) + return FALSE; + + if (!pull_matches_subdir (pull_data, path, dirname, TRUE)) + continue; + + const guchar *tree_csum_bytes = ostree_checksum_bytes_peek_validate (tree_csum, error); + if (tree_csum_bytes == NULL) + return FALSE; + + const guchar *meta_csum_bytes = ostree_checksum_bytes_peek_validate (meta_csum, error); + if (meta_csum_bytes == NULL) + return FALSE; + + g_autofree char *subpath = g_strconcat (path, dirname, "/", NULL); + queue_scan_one_metadata_object_c (pull_data, tree_csum_bytes, + OSTREE_OBJECT_TYPE_DIR_TREE, subpath, recursion_depth + 1, NULL); + queue_scan_one_metadata_object_c (pull_data, meta_csum_bytes, + OSTREE_OBJECT_TYPE_DIR_META, subpath, recursion_depth + 1, NULL); + } + + return TRUE; +} + +/* Given a @ref, fetch its contents (should be a SHA256 ASCII string) */ +static gboolean +fetch_ref_contents (OtPullData *pull_data, + const char *main_collection_id, + const OstreeCollectionRef *ref, + char **out_contents, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *ret_contents = NULL; + + if (pull_data->remote_repo_local != NULL && ref->collection_id != NULL) + { + if (!ostree_repo_resolve_collection_ref (pull_data->remote_repo_local, + ref, FALSE, + OSTREE_REPO_RESOLVE_REV_EXT_NONE, + &ret_contents, cancellable, error)) + return FALSE; + } + else if (pull_data->remote_repo_local != NULL) + { + if (!ostree_repo_resolve_rev_ext (pull_data->remote_repo_local, + ref->ref_name, FALSE, + OSTREE_REPO_RESOLVE_REV_EXT_NONE, + &ret_contents, error)) + return FALSE; + } + else + { + g_autofree char *filename = NULL; + + if (ref->collection_id == NULL || g_strcmp0 (ref->collection_id, main_collection_id) == 0) + filename = g_build_filename ("refs", "heads", ref->ref_name, NULL); + else + filename = g_build_filename ("refs", "mirrors", ref->collection_id, ref->ref_name, NULL); + + if (!fetch_mirrored_uri_contents_utf8_sync (pull_data->fetcher, + pull_data->meta_mirrorlist, + filename, pull_data->n_network_retries, + &ret_contents, + cancellable, error)) + return FALSE; + + g_strchomp (ret_contents); + } + + g_assert (ret_contents); + + if (!ostree_validate_checksum_string (ret_contents, error)) + return glnx_prefix_error (error, "Fetching checksum for ref (%s, %s)", + ref->collection_id ?: "(empty)", + ref->ref_name); + + ot_transfer_out_value (out_contents, &ret_contents); + return TRUE; +} + +static gboolean +lookup_commit_checksum_and_collection_from_summary (OtPullData *pull_data, + const OstreeCollectionRef *ref, + char **out_checksum, + gsize *out_size, + char **out_collection_id, + GError **error) +{ + g_autoptr(GVariant) additional_metadata = g_variant_get_child_value (pull_data->summary, 1); + const gchar *main_collection_id; + + if (!g_variant_lookup (additional_metadata, OSTREE_SUMMARY_COLLECTION_ID, "&s", &main_collection_id)) + main_collection_id = NULL; + + g_autoptr(GVariant) refs = NULL; + const gchar *resolved_collection_id = NULL; + + if (ref->collection_id == NULL || g_strcmp0 (ref->collection_id, main_collection_id) == 0) + { + refs = g_variant_get_child_value (pull_data->summary, 0); + resolved_collection_id = main_collection_id; + } + else if (ref->collection_id != NULL) + { + g_autoptr(GVariant) collection_map = NULL; + + collection_map = g_variant_lookup_value (additional_metadata, OSTREE_SUMMARY_COLLECTION_MAP, + G_VARIANT_TYPE ("a{sa(s(taya{sv}))}")); + if (collection_map != NULL) + refs = g_variant_lookup_value (collection_map, ref->collection_id, G_VARIANT_TYPE ("a(s(taya{sv}))")); + resolved_collection_id = ref->collection_id; + } + + int i; + if (refs == NULL || !ot_variant_bsearch_str (refs, ref->ref_name, &i)) + { + if (ref->collection_id != NULL) + return glnx_throw (error, "No such branch (%s, %s) in repository summary", ref->collection_id, ref->ref_name); + else + return glnx_throw (error, "No such branch '%s' in repository summary", ref->ref_name); + } + + g_autoptr(GVariant) refdata = g_variant_get_child_value (refs, i); + g_autoptr(GVariant) reftargetdata = g_variant_get_child_value (refdata, 1); + guint64 commit_size; + g_autoptr(GVariant) commit_csum_v = NULL; + g_variant_get (reftargetdata, "(t@ay@a{sv})", &commit_size, &commit_csum_v, NULL); + + if (resolved_collection_id != NULL && + !ostree_validate_collection_id (resolved_collection_id, error)) + return FALSE; + if (!ostree_validate_structureof_csum_v (commit_csum_v, error)) + return FALSE; + + *out_checksum = ostree_checksum_from_bytes_v (commit_csum_v); + *out_size = commit_size; + *out_collection_id = g_strdup (resolved_collection_id); + return TRUE; +} + +static void +fetch_object_data_free (FetchObjectData *fetch_data) +{ + g_variant_unref (fetch_data->object); + g_free (fetch_data->path); + if (fetch_data->requested_ref) + ostree_collection_ref_free (fetch_data->requested_ref); + g_free (fetch_data); +} + +static void +content_fetch_on_write_complete (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + FetchObjectData *fetch_data = user_data; + OtPullData *pull_data = fetch_data->pull_data; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + OstreeObjectType objtype; + const char *expected_checksum; + g_autofree guchar *csum = NULL; + g_autofree char *checksum = NULL; + g_autofree char *checksum_obj = NULL; + + if (!ostree_repo_write_content_finish ((OstreeRepo*)object, result, + &csum, error)) + goto out; + + checksum = ostree_checksum_from_bytes (csum); + + ostree_object_name_deserialize (fetch_data->object, &expected_checksum, &objtype); + g_assert (objtype == OSTREE_OBJECT_TYPE_FILE); + + checksum_obj = ostree_object_to_string (checksum, objtype); + g_debug ("write of %s complete", checksum_obj); + + if (!_ostree_compare_object_checksum (objtype, expected_checksum, checksum, error)) + goto out; + + pull_data->n_fetched_content++; + /* Was this a delta fallback? */ + if (g_hash_table_remove (pull_data->requested_fallback_content, expected_checksum)) + pull_data->n_fetched_deltapart_fallbacks++; + out: + pull_data->n_outstanding_content_write_requests--; + /* No retries for local writes. */ + check_outstanding_requests_handle_error (pull_data, &local_error); + fetch_object_data_free (fetch_data); +} + +static void +content_fetch_on_complete (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + OstreeFetcher *fetcher = (OstreeFetcher *)object; + FetchObjectData *fetch_data = user_data; + OtPullData *pull_data = fetch_data->pull_data; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + GCancellable *cancellable = NULL; + guint64 length; + g_auto(GLnxTmpfile) tmpf = { 0, }; + g_autoptr(GInputStream) tmpf_input = NULL; + g_autoptr(GFileInfo) file_info = NULL; + g_autoptr(GVariant) xattrs = NULL; + g_autoptr(GInputStream) file_in = NULL; + g_autoptr(GInputStream) object_input = NULL; + const char *checksum; + g_autofree char *checksum_obj = NULL; + OstreeObjectType objtype; + gboolean free_fetch_data = TRUE; + + if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &tmpf, error)) + goto out; + + ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype); + g_assert (objtype == OSTREE_OBJECT_TYPE_FILE); + + checksum_obj = ostree_object_to_string (checksum, objtype); + g_debug ("fetch of %s complete", checksum_obj); + + const gboolean verifying_bareuseronly = + (pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY) > 0; + + /* See comments where we set this variable; this is implementing + * the --trusted-http/OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP flags. + */ + if (pull_data->trusted_http_direct) + { + g_assert (!verifying_bareuseronly); + if (!_ostree_repo_commit_tmpf_final (pull_data->repo, checksum, objtype, + &tmpf, cancellable, error)) + goto out; + pull_data->n_fetched_content++; + } + else + { + struct stat stbuf; + if (!glnx_fstat (tmpf.fd, &stbuf, error)) + goto out; + /* Non-mirroring path */ + tmpf_input = g_unix_input_stream_new (glnx_steal_fd (&tmpf.fd), TRUE); + + /* If it appears corrupted, we'll delete it below */ + if (!ostree_content_stream_parse (TRUE, tmpf_input, stbuf.st_size, FALSE, + &file_in, &file_info, &xattrs, + cancellable, error)) + { + g_prefix_error (error, "Parsing %s: ", checksum_obj); + goto out; + } + + if (verifying_bareuseronly) + { + if (!_ostree_validate_bareuseronly_mode_finfo (file_info, checksum, error)) + goto out; + } + + if (!ostree_raw_file_to_content_stream (file_in, file_info, xattrs, + &object_input, &length, + cancellable, error)) + goto out; + + pull_data->n_outstanding_content_write_requests++; + ostree_repo_write_content_async (pull_data->repo, checksum, + object_input, length, + cancellable, + content_fetch_on_write_complete, fetch_data); + free_fetch_data = FALSE; + } + + out: + g_assert (pull_data->n_outstanding_content_fetches > 0); + pull_data->n_outstanding_content_fetches--; + + if (_ostree_fetcher_should_retry_request (local_error, fetch_data->n_retries_remaining--)) + enqueue_one_object_request_s (pull_data, g_steal_pointer (&fetch_data)); + else + check_outstanding_requests_handle_error (pull_data, &local_error); + + if (free_fetch_data) + g_clear_pointer (&fetch_data, fetch_object_data_free); +} + +static void +on_metadata_written (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + FetchObjectData *fetch_data = user_data; + OtPullData *pull_data = fetch_data->pull_data; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + const char *expected_checksum; + OstreeObjectType objtype; + g_autofree char *checksum = NULL; + g_autofree guchar *csum = NULL; + g_autofree char *stringified_object = NULL; + + if (!ostree_repo_write_metadata_finish ((OstreeRepo*)object, result, + &csum, error)) + goto out; + + checksum = ostree_checksum_from_bytes (csum); + + ostree_object_name_deserialize (fetch_data->object, &expected_checksum, &objtype); + g_assert (OSTREE_OBJECT_TYPE_IS_META (objtype)); + + stringified_object = ostree_object_to_string (checksum, objtype); + g_debug ("write of %s complete", stringified_object); + + if (strcmp (checksum, expected_checksum) != 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Corrupted metadata object; checksum expected='%s' actual='%s'", + expected_checksum, checksum); + goto out; + } + + queue_scan_one_metadata_object_c (pull_data, csum, objtype, fetch_data->path, 0, fetch_data->requested_ref); + + out: + g_assert (pull_data->n_outstanding_metadata_write_requests > 0); + pull_data->n_outstanding_metadata_write_requests--; + fetch_object_data_free (fetch_data); + + /* No need to retry local write operations. */ + check_outstanding_requests_handle_error (pull_data, &local_error); +} + +static void +meta_fetch_on_complete (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + OstreeFetcher *fetcher = (OstreeFetcher *)object; + FetchObjectData *fetch_data = user_data; + OtPullData *pull_data = fetch_data->pull_data; + g_autoptr(GVariant) metadata = NULL; + g_auto(GLnxTmpfile) tmpf = { 0, }; + const char *checksum; + g_autofree char *checksum_obj = NULL; + OstreeObjectType objtype; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + gboolean free_fetch_data = TRUE; + + ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype); + checksum_obj = ostree_object_to_string (checksum, objtype); + g_debug ("fetch of %s%s complete", checksum_obj, + fetch_data->is_detached_meta ? " (detached)" : ""); + + if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &tmpf, error)) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + if (fetch_data->is_detached_meta) + { + /* There isn't any detached metadata, just fetch the commit */ + g_clear_error (&local_error); + + /* Now that we've at least tried to fetch it, we can proceed to + * scan/fetch the commit object */ + g_hash_table_insert (pull_data->fetched_detached_metadata, g_strdup (checksum), NULL); + + if (!fetch_data->object_is_stored) + enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE, fetch_data->requested_ref); + else + queue_scan_one_metadata_object (pull_data, checksum, objtype, fetch_data->path, 0, fetch_data->requested_ref); + } + + /* When traversing parents, do not fail on a missing commit. + * We may be pulling from a partial repository that ends in + * a dangling parent reference. */ + else if (objtype == OSTREE_OBJECT_TYPE_COMMIT && + pull_data->maxdepth != 0) + { + g_clear_error (&local_error); + /* If the remote repo supports tombstone commits, check if the commit was intentionally + deleted. */ + if (pull_data->has_tombstone_commits) + { + enqueue_one_object_request (pull_data, checksum, OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT, + fetch_data->path, FALSE, FALSE, NULL); + } + } + } + + goto out; + } + + /* Tombstone commits are always empty, so skip all processing here */ + if (objtype == OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT) + goto out; + + if (fetch_data->is_detached_meta) + { + if (!ot_variant_read_fd (tmpf.fd, 0, G_VARIANT_TYPE ("a{sv}"), + FALSE, &metadata, error)) + goto out; + + if (!ostree_repo_write_commit_detached_metadata (pull_data->repo, checksum, metadata, + pull_data->cancellable, error)) + goto out; + + g_hash_table_insert (pull_data->fetched_detached_metadata, g_strdup (checksum), g_steal_pointer (&metadata)); + + if (!fetch_data->object_is_stored) + enqueue_one_object_request (pull_data, checksum, objtype, fetch_data->path, FALSE, FALSE, fetch_data->requested_ref); + else + queue_scan_one_metadata_object (pull_data, checksum, objtype, fetch_data->path, 0, fetch_data->requested_ref); + } + else + { + if (!ot_variant_read_fd (tmpf.fd, 0, ostree_metadata_variant_type (objtype), + FALSE, &metadata, error)) + goto out; + + /* Compute checksum and verify structure now. Note this is a recent change + * (Jan 2018) - we used to verify the checksum only when writing down + * below. But we want to do "structure" verification early on as well + * before the object is written even to the staging directory. + */ + if (!_ostree_verify_metadata_object (objtype, checksum, metadata, error)) + goto out; + + /* For commit objects, check the signature before writing to the repo, + * and also write the .commitpartial to say that we're still processing + * this commit. + */ + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + /* Do signature verification. `detached_data` may be NULL if no detached + * metadata was found during pull; that's handled by + * ostree_ostree_verify_unwritten_commit(). If we ever change the pull code to + * not always fetch detached metadata, this bit will have to learn how + * to look up from the disk state as well, or insert the on-disk + * metadata into this hash. + */ + GVariant *detached_data = g_hash_table_lookup (pull_data->fetched_detached_metadata, checksum); + if (!_verify_unwritten_commit (pull_data, checksum, metadata, detached_data, + fetch_data->requested_ref, pull_data->cancellable, error)) + goto out; + + if (!ostree_repo_mark_commit_partial (pull_data->repo, checksum, TRUE, error)) + goto out; + } + + /* Note that we now (Jan 2018) pass NULL for checksum, which means "don't + * verify checksum", since we just did it above. Related to this...now + * that we're doing all the verification here, one thing we could do later + * just `glnx_link_tmpfile_at()` into the repository, like the content + * fetch path does for trusted commits. + */ + ostree_repo_write_metadata_async (pull_data->repo, objtype, NULL, metadata, + pull_data->cancellable, + on_metadata_written, fetch_data); + pull_data->n_outstanding_metadata_write_requests++; + free_fetch_data = FALSE; + } + + out: + g_assert (pull_data->n_outstanding_metadata_fetches > 0); + pull_data->n_outstanding_metadata_fetches--; + + if (local_error == NULL) + pull_data->n_fetched_metadata++; + + if (_ostree_fetcher_should_retry_request (local_error, fetch_data->n_retries_remaining--)) + enqueue_one_object_request_s (pull_data, g_steal_pointer (&fetch_data)); + else + check_outstanding_requests_handle_error (pull_data, &local_error); + + if (free_fetch_data) + g_clear_pointer (&fetch_data, fetch_object_data_free); +} + +static void +fetch_static_delta_data_free (gpointer data) +{ + FetchStaticDeltaData *fetch_data = data; + g_free (fetch_data->expected_checksum); + g_variant_unref (fetch_data->objects); + g_free (fetch_data->from_revision); + g_free (fetch_data->to_revision); + g_free (fetch_data); +} + +static void +on_static_delta_written (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + FetchStaticDeltaData *fetch_data = user_data; + OtPullData *pull_data = fetch_data->pull_data; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + + g_debug ("execute static delta part %s complete", fetch_data->expected_checksum); + + if (!_ostree_static_delta_part_execute_finish (pull_data->repo, result, error)) + goto out; + + out: + g_assert (pull_data->n_outstanding_deltapart_write_requests > 0); + pull_data->n_outstanding_deltapart_write_requests--; + /* No need to retry on failure to write locally. */ + check_outstanding_requests_handle_error (pull_data, &local_error); + /* Always free state */ + fetch_static_delta_data_free (fetch_data); +} + +static void +static_deltapart_fetch_on_complete (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + OstreeFetcher *fetcher = (OstreeFetcher *)object; + FetchStaticDeltaData *fetch_data = user_data; + OtPullData *pull_data = fetch_data->pull_data; + g_auto(GLnxTmpfile) tmpf = { 0, }; + g_autoptr(GInputStream) in = NULL; + g_autoptr(GVariant) part = NULL; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + gboolean free_fetch_data = TRUE; + + g_debug ("fetch static delta part %s complete", fetch_data->expected_checksum); + + if (!_ostree_fetcher_request_to_tmpfile_finish (fetcher, result, &tmpf, error)) + goto out; + + /* Transfer ownership of the fd */ + in = g_unix_input_stream_new (glnx_steal_fd (&tmpf.fd), TRUE); + + /* TODO - make async */ + if (!_ostree_static_delta_part_open (in, NULL, 0, fetch_data->expected_checksum, + &part, pull_data->cancellable, error)) + goto out; + + _ostree_static_delta_part_execute_async (pull_data->repo, + fetch_data->objects, + part, + pull_data->cancellable, + on_static_delta_written, + fetch_data); + pull_data->n_outstanding_deltapart_write_requests++; + free_fetch_data = FALSE; + + out: + g_assert (pull_data->n_outstanding_deltapart_fetches > 0); + pull_data->n_outstanding_deltapart_fetches--; + + if (local_error == NULL) + pull_data->n_fetched_deltaparts++; + + if (_ostree_fetcher_should_retry_request (local_error, fetch_data->n_retries_remaining--)) + enqueue_one_static_delta_part_request_s (pull_data, g_steal_pointer (&fetch_data)); + else + check_outstanding_requests_handle_error (pull_data, &local_error); + + if (free_fetch_data) + g_clear_pointer (&fetch_data, fetch_static_delta_data_free); +} + +static gboolean +commitstate_is_partial (OtPullData *pull_data, + OstreeRepoCommitState commitstate) +{ + return pull_data->legacy_transaction_resuming + || (commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) > 0; +} + +#endif /* HAVE_LIBCURL_OR_LIBSOUP */ + +/* Reads the collection-id of a given remote from the repo + * configuration. + */ +static char * +get_real_remote_repo_collection_id (OstreeRepo *repo, + const gchar *remote_name) +{ + /* remote_name == NULL can happen for pull-local */ + if (!remote_name) + return NULL; + + g_autofree gchar *remote_collection_id = NULL; + if (!ostree_repo_get_remote_option (repo, remote_name, "collection-id", NULL, + &remote_collection_id, NULL) || + (remote_collection_id == NULL) || + (remote_collection_id[0] == '\0')) + return NULL; + + return g_steal_pointer (&remote_collection_id); +} + +#ifdef HAVE_LIBCURL_OR_LIBSOUP + +/* Reads the collection-id of the remote repo. Where it will be read + * from depends on whether we pull from the "local" remote repo (the + * "file://" URL) or "remote" remote repo (likely the "http(s)://" + * URL). + */ +static char * +get_remote_repo_collection_id (OtPullData *pull_data) +{ + if (pull_data->remote_repo_local != NULL) + { + const char *remote_collection_id = + ostree_repo_get_collection_id (pull_data->remote_repo_local); + if ((remote_collection_id == NULL) || + (remote_collection_id[0] == '\0')) + return NULL; + return g_strdup (remote_collection_id); + } + + return get_real_remote_repo_collection_id (pull_data->repo, + pull_data->remote_name); +} + +#endif /* HAVE_LIBCURL_OR_LIBSOUP */ + +/* Check whether the given remote exists, has a `collection-id` key set, and it + * equals @collection_id. If so, return %TRUE. Otherwise, %FALSE. */ +static gboolean +check_remote_matches_collection_id (OstreeRepo *repo, + const gchar *remote_name, + const gchar *collection_id) +{ + g_autofree gchar *remote_collection_id = NULL; + + remote_collection_id = get_real_remote_repo_collection_id (repo, remote_name); + if (remote_collection_id == NULL) + return FALSE; + + return g_str_equal (remote_collection_id, collection_id); +} + +/** + * ostree_repo_resolve_keyring_for_collection: + * @self: an #OstreeRepo + * @collection_id: the collection ID to look up a keyring for + * @cancellable: (nullable): a #GCancellable, or %NULL + * @error: return location for a #GError, or %NULL + * + * Find the GPG keyring for the given @collection_id, using the local + * configuration from the given #OstreeRepo. This will search the configured + * remotes for ones whose `collection-id` key matches @collection_id, and will + * return the first matching remote. + * + * If multiple remotes match and have different keyrings, a debug message will + * be emitted, and the first result will be returned. It is expected that the + * keyrings should match. + * + * If no match can be found, a %G_IO_ERROR_NOT_FOUND error will be returned. + * + * Returns: (transfer full): #OstreeRemote containing the GPG keyring for + * @collection_id + * Since: 2018.6 + */ +OstreeRemote * +ostree_repo_resolve_keyring_for_collection (OstreeRepo *self, + const gchar *collection_id, + GCancellable *cancellable, + GError **error) +{ +#ifndef OSTREE_DISABLE_GPGME + gsize i; + g_auto(GStrv) remotes = NULL; + g_autoptr(OstreeRemote) keyring_remote = NULL; + + g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); + g_return_val_if_fail (ostree_validate_collection_id (collection_id, NULL), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* Look through all the currently configured remotes for the given collection. */ + remotes = ostree_repo_remote_list (self, NULL); + + for (i = 0; remotes != NULL && remotes[i] != NULL; i++) + { + g_autoptr(GError) local_error = NULL; + + if (!check_remote_matches_collection_id (self, remotes[i], collection_id)) + continue; + + if (keyring_remote == NULL) + { + g_debug ("%s: Found match for collection ‘%s’ in remote ‘%s’.", + G_STRFUNC, collection_id, remotes[i]); + keyring_remote = _ostree_repo_get_remote_inherited (self, remotes[i], &local_error); + + if (keyring_remote == NULL) + { + g_debug ("%s: Error loading remote ‘%s’: %s", + G_STRFUNC, remotes[i], local_error->message); + continue; + } + + if (g_strcmp0 (keyring_remote->keyring, "") == 0 || + g_strcmp0 (keyring_remote->keyring, "/dev/null") == 0) + { + g_debug ("%s: Ignoring remote ‘%s’ as it has no keyring configured.", + G_STRFUNC, remotes[i]); + g_clear_object (&keyring_remote); + continue; + } + + /* continue so we can catch duplicates */ + } + else + { + g_debug ("%s: Duplicate keyring for collection ‘%s’ in remote ‘%s’." + "Keyring will be loaded from remote ‘%s’.", + G_STRFUNC, collection_id, remotes[i], + keyring_remote->name); + } + } + + if (keyring_remote != NULL) + return g_steal_pointer (&keyring_remote); + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No keyring found configured locally for collection ‘%s’", + collection_id); + return NULL; + } +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "'%s': GPG feature is disabled in a build time", + __FUNCTION__); + return NULL; +#endif /* OSTREE_DISABLE_GPGME */ +} + +#ifdef HAVE_LIBCURL_OR_LIBSOUP + +/* Look at a commit object, and determine whether there are + * more things to fetch. + */ +static gboolean +scan_commit_object (OtPullData *pull_data, + const char *checksum, + guint recursion_depth, + const OstreeCollectionRef *ref, + GCancellable *cancellable, + GError **error) +{ + gpointer depthp; + gint depth; + if (g_hash_table_lookup_extended (pull_data->commit_to_depth, checksum, + NULL, &depthp)) + { + depth = GPOINTER_TO_INT (depthp); + } + else + { + depth = pull_data->maxdepth; + g_hash_table_insert (pull_data->commit_to_depth, g_strdup (checksum), + GINT_TO_POINTER (depth)); + } + +#ifndef OSTREE_DISABLE_GPGME + /* See comment in process_verify_result() - we now gpg check before writing, + * but also ensure we've done it here if not already. + */ + if (pull_data->gpg_verify && + !g_hash_table_contains (pull_data->verified_commits, checksum)) + { + g_autoptr(OstreeGpgVerifyResult) result = NULL; + const char *keyring_remote = NULL; + + if (ref != NULL) + keyring_remote = g_hash_table_lookup (pull_data->ref_keyring_map, ref); + if (keyring_remote == NULL) + keyring_remote = pull_data->remote_name; + + result = ostree_repo_verify_commit_for_remote (pull_data->repo, + checksum, + keyring_remote, + cancellable, + error); + if (!_process_gpg_verify_result (pull_data, checksum, result, error)) + return FALSE; + } +#endif /* OSTREE_DISABLE_GPGME */ + + if (pull_data->signapi_commit_verifiers && + !g_hash_table_contains (pull_data->signapi_verified_commits, checksum)) + { + g_autoptr(GError) last_verification_error = NULL; + gboolean found_any_signature = FALSE; + gboolean found_valid_signature = FALSE; + g_autofree char *success_message = NULL; + + for (guint i = 0; i < pull_data->signapi_commit_verifiers->len; i++) + { + OstreeSign *sign = pull_data->signapi_commit_verifiers->pdata[i]; + + found_any_signature = TRUE; + + /* Set return to true if any sign fit */ + if (ostree_sign_commit_verify (sign, + pull_data->repo, + checksum, + &success_message, + cancellable, + last_verification_error ? NULL : &last_verification_error)) + { + found_valid_signature = TRUE; + break; + } + } + + if (!found_any_signature) + return glnx_throw (error, "No signatures found for commit %s", checksum); + + if (!found_valid_signature) + { + g_assert (last_verification_error); + g_propagate_error (error, g_steal_pointer (&last_verification_error)); + return glnx_prefix_error (error, "Can't verify commit %s", checksum); + } + g_assert (success_message); + g_hash_table_insert (pull_data->signapi_verified_commits, g_strdup (checksum), g_steal_pointer (&success_message)); + } + + /* If we found a legacy transaction flag, assume we have to scan. + * We always do a scan of dirtree objects; see + * https://github.com/ostreedev/ostree/issues/543 + */ + OstreeRepoCommitState commitstate; + g_autoptr(GVariant) commit = NULL; + if (!ostree_repo_load_commit (pull_data->repo, checksum, &commit, &commitstate, error)) + return FALSE; + + /* If ref is non-NULL then the commit we fetched was requested through the + * branch, otherwise we requested a commit checksum without specifying a branch. + */ + g_autofree char *remote_collection_id = NULL; + remote_collection_id = get_remote_repo_collection_id (pull_data); + if (!_ostree_repo_verify_bindings (remote_collection_id, + (ref != NULL) ? ref->ref_name : NULL, + commit, error)) + return glnx_prefix_error (error, "Commit %s", checksum); + + guint64 new_ts = ostree_commit_get_timestamp (commit); + if (pull_data->timestamp_check) + { + /* We don't support timestamp checking while recursing right now */ + g_assert (ref); + g_assert_cmpint (recursion_depth, ==, 0); + const char *orig_rev = NULL; + if (!g_hash_table_lookup_extended (pull_data->ref_original_commits, + ref, NULL, (void**)&orig_rev)) + g_assert_not_reached (); + + g_autoptr(GVariant) orig_commit = NULL; + if (orig_rev) + { + if (!ostree_repo_load_commit (pull_data->repo, orig_rev, + &orig_commit, NULL, error)) + return glnx_prefix_error (error, "Reading %s for timestamp-check", ref->ref_name); + + guint64 orig_ts = ostree_commit_get_timestamp (orig_commit); + if (!_ostree_compare_timestamps (orig_rev, orig_ts, checksum, new_ts, error)) + return FALSE; + } + } + if (pull_data->timestamp_check_from_rev) + { + g_autoptr(GVariant) commit = NULL; + if (!ostree_repo_load_commit (pull_data->repo, pull_data->timestamp_check_from_rev, + &commit, NULL, error)) + return glnx_prefix_error (error, "Reading %s for timestamp-check-from-rev", + pull_data->timestamp_check_from_rev); + + guint64 ts = ostree_commit_get_timestamp (commit); + if (!_ostree_compare_timestamps (pull_data->timestamp_check_from_rev, ts, checksum, new_ts, error)) + return FALSE; + } + + /* If we found a legacy transaction flag, assume all commits are partial */ + gboolean is_partial = commitstate_is_partial (pull_data, commitstate); + + /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */ + g_autoptr(GVariant) parent_csum = NULL; + const guchar *parent_csum_bytes = NULL; + g_variant_get_child (commit, 1, "@ay", &parent_csum); + if (g_variant_n_children (parent_csum) > 0) + { + parent_csum_bytes = ostree_checksum_bytes_peek_validate (parent_csum, error); + if (parent_csum_bytes == NULL) + return FALSE; + } + + if (parent_csum_bytes != NULL && pull_data->maxdepth == -1) + { + queue_scan_one_metadata_object_c (pull_data, parent_csum_bytes, + OSTREE_OBJECT_TYPE_COMMIT, NULL, + recursion_depth + 1, NULL); + } + else if (parent_csum_bytes != NULL && depth > 0) + { + char parent_checksum[OSTREE_SHA256_STRING_LEN+1]; + gpointer parent_depthp; + int parent_depth; + + ostree_checksum_inplace_from_bytes (parent_csum_bytes, parent_checksum); + + if (g_hash_table_lookup_extended (pull_data->commit_to_depth, parent_checksum, + NULL, &parent_depthp)) + { + parent_depth = GPOINTER_TO_INT (parent_depthp); + } + else + { + parent_depth = depth - 1; + } + + if (parent_depth >= 0) + { + g_hash_table_insert (pull_data->commit_to_depth, g_strdup (parent_checksum), + GINT_TO_POINTER (parent_depth)); + queue_scan_one_metadata_object_c (pull_data, parent_csum_bytes, + OSTREE_OBJECT_TYPE_COMMIT, + NULL, + recursion_depth + 1, + NULL); + } + } + + /* We only recurse to looking whether we need dirtree/dirmeta + * objects if the commit is partial, and we're not doing a + * commit-only fetch. + */ + if (is_partial && !pull_data->is_commit_only) + { + g_autoptr(GVariant) tree_contents_csum = NULL; + g_autoptr(GVariant) tree_meta_csum = NULL; + const guchar *tree_contents_csum_bytes; + const guchar *tree_meta_csum_bytes; + + g_variant_get_child (commit, 6, "@ay", &tree_contents_csum); + g_variant_get_child (commit, 7, "@ay", &tree_meta_csum); + + tree_contents_csum_bytes = ostree_checksum_bytes_peek_validate (tree_contents_csum, error); + if (tree_contents_csum_bytes == NULL) + return FALSE; + + tree_meta_csum_bytes = ostree_checksum_bytes_peek_validate (tree_meta_csum, error); + if (tree_meta_csum_bytes == NULL) + return FALSE; + + queue_scan_one_metadata_object_c (pull_data, tree_contents_csum_bytes, + OSTREE_OBJECT_TYPE_DIR_TREE, "/", recursion_depth + 1, NULL); + + queue_scan_one_metadata_object_c (pull_data, tree_meta_csum_bytes, + OSTREE_OBJECT_TYPE_DIR_META, NULL, recursion_depth + 1, NULL); + } + + return TRUE; +} + +static void +queue_scan_one_metadata_object (OtPullData *pull_data, + const char *csum, + OstreeObjectType objtype, + const char *path, + guint recursion_depth, + const OstreeCollectionRef *ref) +{ + guchar buf[OSTREE_SHA256_DIGEST_LEN]; + ostree_checksum_inplace_to_bytes (csum, buf); + queue_scan_one_metadata_object_c (pull_data, buf, objtype, path, recursion_depth, ref); +} + +static void +queue_scan_one_metadata_object_s (OtPullData *pull_data, + ScanObjectQueueData *scan_data) +{ + g_queue_push_tail (&pull_data->scan_object_queue, scan_data); + ensure_idle_queued (pull_data); +} + +static void +queue_scan_one_metadata_object_c (OtPullData *pull_data, + const guchar *csum, + OstreeObjectType objtype, + const char *path, + guint recursion_depth, + const OstreeCollectionRef *ref) +{ + ScanObjectQueueData *scan_data = g_new0 (ScanObjectQueueData, 1); + + memcpy (scan_data->csum, csum, sizeof (scan_data->csum)); + scan_data->objtype = objtype; + scan_data->path = g_strdup (path); + scan_data->recursion_depth = recursion_depth; + scan_data->requested_ref = (ref != NULL) ? ostree_collection_ref_dup (ref) : NULL; + + queue_scan_one_metadata_object_s (pull_data, g_steal_pointer (&scan_data)); +} + +/* Called out of the main loop to look at metadata objects which can have + * further references (commit, dirtree). See also idle_worker() which drives + * execution of this function. + */ +static gboolean +scan_one_metadata_object (OtPullData *pull_data, + const char *checksum, + OstreeObjectType objtype, + const char *path, + guint recursion_depth, + const OstreeCollectionRef *ref, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) object = ostree_object_name_serialize (checksum, objtype); + + /* It may happen that we've already looked at this object (think shared + * dirtree subtrees), if that's the case, we're done */ + if (g_hash_table_lookup (pull_data->scanned_metadata, object)) + return TRUE; + + gboolean is_requested = g_hash_table_lookup (pull_data->requested_metadata, object) != NULL; + /* Determine if we already have the object */ + gboolean is_stored; + if (!ostree_repo_has_object (pull_data->repo, objtype, checksum, &is_stored, + cancellable, error)) + return FALSE; + + /* Are we pulling an object we don't have from a local repo? */ + if (!is_stored && pull_data->remote_repo_local) + { + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + /* mark as partial to ensure we scan the commit below */ + if (!ostree_repo_mark_commit_partial (pull_data->repo, checksum, TRUE, error)) + return FALSE; + } + + if (!_ostree_repo_import_object (pull_data->repo, pull_data->remote_repo_local, + objtype, checksum, pull_data->importflags, + cancellable, error)) + return FALSE; + /* The import API will fetch both the commit and detached metadata, so + * add it to the hash to avoid re-fetching it below. + */ + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + g_hash_table_insert (pull_data->fetched_detached_metadata, g_strdup (checksum), NULL); + pull_data->n_imported_metadata++; + is_stored = TRUE; + is_requested = TRUE; + } + /* Do we have any localcache repos? */ + else if (!is_stored && pull_data->localcache_repos) + { + for (guint i = 0; i < pull_data->localcache_repos->len; i++) + { + OstreeRepo *refd_repo = pull_data->localcache_repos->pdata[i]; + gboolean localcache_repo_has_obj; + + if (!ostree_repo_has_object (refd_repo, objtype, checksum, + &localcache_repo_has_obj, cancellable, error)) + return FALSE; + if (!localcache_repo_has_obj) + continue; + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + /* mark as partial to ensure we scan the commit below */ + if (!ostree_repo_mark_commit_partial (pull_data->repo, checksum, TRUE, error)) + return FALSE; + } + if (!_ostree_repo_import_object (pull_data->repo, refd_repo, + objtype, checksum, pull_data->importflags, + cancellable, error)) + return FALSE; + /* See comment above */ + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + g_hash_table_insert (pull_data->fetched_detached_metadata, g_strdup (checksum), NULL); + is_stored = TRUE; + is_requested = TRUE; + pull_data->n_imported_metadata++; + break; + } + } + + if (!is_stored && !is_requested) + { + gboolean do_fetch_detached; + + g_hash_table_add (pull_data->requested_metadata, g_variant_ref (object)); + + do_fetch_detached = (objtype == OSTREE_OBJECT_TYPE_COMMIT); + enqueue_one_object_request (pull_data, checksum, objtype, path, do_fetch_detached, FALSE, ref); + } + else if (is_stored && objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + /* Even though we already have the commit, we always try to (re)fetch the + * detached metadata before scanning it, in case new signatures appear. + * https://github.com/projectatomic/rpm-ostree/issues/630 */ + if (!g_hash_table_contains (pull_data->fetched_detached_metadata, checksum)) + enqueue_one_object_request (pull_data, checksum, objtype, path, TRUE, TRUE, ref); + else + { + if (!scan_commit_object (pull_data, checksum, recursion_depth, ref, + pull_data->cancellable, error)) + return FALSE; + + g_hash_table_add (pull_data->scanned_metadata, g_variant_ref (object)); + pull_data->n_scanned_metadata++; + } + } + else if (is_stored && objtype == OSTREE_OBJECT_TYPE_DIR_TREE) + { + if (!scan_dirtree_object (pull_data, checksum, path, recursion_depth, + pull_data->cancellable, error)) + return FALSE; + + g_hash_table_add (pull_data->scanned_metadata, g_variant_ref (object)); + pull_data->n_scanned_metadata++; + } + + return TRUE; +} + +static void +enqueue_one_object_request_s (OtPullData *pull_data, + FetchObjectData *fetch_data) +{ + const char *checksum; + OstreeObjectType objtype; + + ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype); + gboolean is_meta = OSTREE_OBJECT_TYPE_IS_META (objtype); + + /* Are too many requests are in flight? */ + if (fetcher_queue_is_full (pull_data)) + { + g_debug ("queuing fetch of %s.%s%s", checksum, + ostree_object_type_to_string (objtype), + fetch_data->is_detached_meta ? " (detached)" : ""); + + if (is_meta) + { + g_hash_table_insert (pull_data->pending_fetch_metadata, g_variant_ref (fetch_data->object), fetch_data); + } + else + { + g_hash_table_insert (pull_data->pending_fetch_content, g_strdup (checksum), fetch_data); + } + } + else + { + start_fetch (pull_data, fetch_data); + } +} + +static void +enqueue_one_object_request (OtPullData *pull_data, + const char *checksum, + OstreeObjectType objtype, + const char *path, + gboolean is_detached_meta, + gboolean object_is_stored, + const OstreeCollectionRef *ref) +{ + FetchObjectData *fetch_data; + + fetch_data = g_new0 (FetchObjectData, 1); + fetch_data->pull_data = pull_data; + fetch_data->object = ostree_object_name_serialize (checksum, objtype); + fetch_data->path = g_strdup (path); + fetch_data->is_detached_meta = is_detached_meta; + fetch_data->object_is_stored = object_is_stored; + fetch_data->requested_ref = (ref != NULL) ? ostree_collection_ref_dup (ref) : NULL; + fetch_data->n_retries_remaining = pull_data->n_network_retries; + + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + pull_data->n_requested_metadata++; + else + pull_data->n_requested_content++; + + enqueue_one_object_request_s (pull_data, g_steal_pointer (&fetch_data)); +} + +static void +start_fetch (OtPullData *pull_data, + FetchObjectData *fetch) +{ + g_autofree char *obj_subpath = NULL; + guint64 *expected_max_size_p; + guint64 expected_max_size; + const char *expected_checksum; + OstreeObjectType objtype; + GPtrArray *mirrorlist = NULL; + + ostree_object_name_deserialize (fetch->object, &expected_checksum, &objtype); + + g_debug ("starting fetch of %s.%s%s", expected_checksum, + ostree_object_type_to_string (objtype), + fetch->is_detached_meta ? " (detached)" : ""); + + gboolean is_meta = OSTREE_OBJECT_TYPE_IS_META (objtype); + if (is_meta) + pull_data->n_outstanding_metadata_fetches++; + else + pull_data->n_outstanding_content_fetches++; + + OstreeFetcherRequestFlags flags = 0; + /* Override the path if we're trying to fetch the .commitmeta file first */ + if (fetch->is_detached_meta) + { + char buf[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (buf, expected_checksum, OSTREE_OBJECT_TYPE_COMMIT_META, pull_data->remote_mode); + obj_subpath = g_build_filename ("objects", buf, NULL); + mirrorlist = pull_data->meta_mirrorlist; + flags |= OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT; + } + else + { + obj_subpath = _ostree_get_relative_object_path (expected_checksum, objtype, TRUE); + mirrorlist = pull_data->content_mirrorlist; + } + + /* We may have determined maximum sizes from the summary file content; if so, + * honor it. Otherwise, metadata has a baseline max size. + */ + expected_max_size_p = fetch->is_detached_meta ? NULL : g_hash_table_lookup (pull_data->expected_commit_sizes, expected_checksum); + if (expected_max_size_p) + expected_max_size = *expected_max_size_p; + else if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + expected_max_size = pull_data->max_metadata_size; + else + expected_max_size = 0; + + if (!is_meta && pull_data->trusted_http_direct) + flags |= OSTREE_FETCHER_REQUEST_LINKABLE; + _ostree_fetcher_request_to_tmpfile (pull_data->fetcher, mirrorlist, + obj_subpath, flags, expected_max_size, + is_meta ? OSTREE_REPO_PULL_METADATA_PRIORITY + : OSTREE_REPO_PULL_CONTENT_PRIORITY, + pull_data->cancellable, + is_meta ? meta_fetch_on_complete : content_fetch_on_complete, fetch); +} + +static gboolean +load_remote_repo_config (OtPullData *pull_data, + GKeyFile **out_keyfile, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *contents = NULL; + + if (!fetch_mirrored_uri_contents_utf8_sync (pull_data->fetcher, + pull_data->meta_mirrorlist, + "config", pull_data->n_network_retries, + &contents, cancellable, error)) + return FALSE; + + g_autoptr(GKeyFile) ret_keyfile = g_key_file_new (); + if (!g_key_file_load_from_data (ret_keyfile, contents, strlen (contents), + 0, error)) + return glnx_prefix_error (error, "Parsing config"); + + ot_transfer_out_value (out_keyfile, &ret_keyfile); + return TRUE; +} + +static gboolean +process_one_static_delta_fallback (OtPullData *pull_data, + gboolean delta_byteswap, + GVariant *fallback_object, + GCancellable *cancellable, + GError **error) +{ + guint8 objtype_y; + g_autoptr(GVariant) csum_v = NULL; + guint64 compressed_size, uncompressed_size; + + g_variant_get (fallback_object, "(y@aytt)", + &objtype_y, &csum_v, &compressed_size, &uncompressed_size); + + if (!ostree_validate_structureof_objtype (objtype_y, error)) + return FALSE; + if (!ostree_validate_structureof_csum_v (csum_v, error)) + return FALSE; + + compressed_size = maybe_swap_endian_u64 (delta_byteswap, compressed_size); + uncompressed_size = maybe_swap_endian_u64 (delta_byteswap, uncompressed_size); + + pull_data->n_total_delta_fallbacks += 1; + pull_data->total_deltapart_size += compressed_size; + pull_data->total_deltapart_usize += uncompressed_size; + + OstreeObjectType objtype = (OstreeObjectType)objtype_y; + g_autofree char *checksum = ostree_checksum_from_bytes_v (csum_v); + + gboolean is_stored; + if (!ostree_repo_has_object (pull_data->repo, objtype, checksum, + &is_stored, + cancellable, error)) + return FALSE; + + if (is_stored) + pull_data->fetched_deltapart_size += compressed_size; + + if (pull_data->dry_run) + return TRUE; /* Note early return */ + + if (!is_stored) + { + /* The delta compiler never did this, there's no reason to support it */ + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + return glnx_throw (error, "Found metadata object as fallback: %s.%s", checksum, + ostree_object_type_to_string (objtype)); + else + { + if (!g_hash_table_lookup (pull_data->requested_content, checksum)) + { + /* Mark this as requested, like we do in the non-delta path */ + g_hash_table_add (pull_data->requested_content, checksum); + /* But also record it's a delta fallback object, so we can account + * for it as logically part of the delta fetch. + */ + g_hash_table_add (pull_data->requested_fallback_content, g_strdup (checksum)); + enqueue_one_object_request (pull_data, checksum, OSTREE_OBJECT_TYPE_FILE, NULL, FALSE, FALSE, NULL); + checksum = NULL; /* We transferred ownership to the requested_content hash */ + } + } + } + + return TRUE; +} + +static void +enqueue_one_static_delta_part_request_s (OtPullData *pull_data, + FetchStaticDeltaData *fetch_data) +{ + if (fetcher_queue_is_full (pull_data)) + { + g_debug ("queuing fetch of static delta %s-%s part %u", + fetch_data->from_revision ?: "empty", + fetch_data->to_revision, fetch_data->i); + + g_hash_table_add (pull_data->pending_fetch_deltaparts, fetch_data); + } + else + { + start_fetch_deltapart (pull_data, fetch_data); + } +} + +static void +start_fetch_deltapart (OtPullData *pull_data, + FetchStaticDeltaData *fetch) +{ + g_autofree char *deltapart_path = _ostree_get_relative_static_delta_part_path (fetch->from_revision, fetch->to_revision, fetch->i); + pull_data->n_outstanding_deltapart_fetches++; + g_assert_cmpint (pull_data->n_outstanding_deltapart_fetches, <=, _OSTREE_MAX_OUTSTANDING_DELTAPART_REQUESTS); + _ostree_fetcher_request_to_tmpfile (pull_data->fetcher, + pull_data->content_mirrorlist, + deltapart_path, 0, fetch->size, + OSTREE_FETCHER_DEFAULT_PRIORITY, + pull_data->cancellable, + static_deltapart_fetch_on_complete, + fetch); +} + +static gboolean +process_one_static_delta (OtPullData *pull_data, + const char *from_revision, + const char *to_revision, + GVariant *delta_superblock, + const OstreeCollectionRef *ref, + GCancellable *cancellable, + GError **error) +{ + gboolean delta_byteswap = _ostree_delta_needs_byteswap (delta_superblock); + + /* Parsing OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT */ + g_autoptr(GVariant) metadata = g_variant_get_child_value (delta_superblock, 0); + g_autoptr(GVariant) headers = g_variant_get_child_value (delta_superblock, 6); + g_autoptr(GVariant) fallback_objects = g_variant_get_child_value (delta_superblock, 7); + + /* Gather free space so we can do a check below */ + struct statvfs stvfsbuf; + if (TEMP_FAILURE_RETRY (fstatvfs (pull_data->repo->repo_dir_fd, &stvfsbuf)) < 0) + return glnx_throw_errno_prefix (error, "fstatvfs"); + + /* First process the fallbacks */ + guint n = g_variant_n_children (fallback_objects); + for (guint i = 0; i < n; i++) + { + g_autoptr(GVariant) fallback_object = + g_variant_get_child_value (fallback_objects, i); + + if (!process_one_static_delta_fallback (pull_data, delta_byteswap, + fallback_object, + cancellable, error)) + return FALSE; + } + + /* Write the to-commit object */ + if (!pull_data->dry_run) + { + g_autoptr(GVariant) to_csum_v = g_variant_get_child_value (delta_superblock, 3); + if (!ostree_validate_structureof_csum_v (to_csum_v, error)) + return FALSE; + g_autofree char *to_checksum = ostree_checksum_from_bytes_v (to_csum_v); + + gboolean have_to_commit; + if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_COMMIT, to_checksum, + &have_to_commit, cancellable, error)) + return FALSE; + + if (!have_to_commit) + { + g_autoptr(GVariant) to_commit = g_variant_get_child_value (delta_superblock, 4); + g_autofree char *detached_path = _ostree_get_relative_static_delta_path (from_revision, to_revision, "commitmeta"); + g_autoptr(GVariant) detached_data = g_variant_lookup_value (metadata, detached_path, G_VARIANT_TYPE("a{sv}")); + + if (!_verify_unwritten_commit (pull_data, to_revision, to_commit, detached_data, + ref, cancellable, error)) + return FALSE; + + if (detached_data && !ostree_repo_write_commit_detached_metadata (pull_data->repo, + to_revision, + detached_data, + cancellable, + error)) + return FALSE; + + FetchObjectData *fetch_data = g_new0 (FetchObjectData, 1); + fetch_data->pull_data = pull_data; + fetch_data->object = ostree_object_name_serialize (to_checksum, OSTREE_OBJECT_TYPE_COMMIT); + fetch_data->is_detached_meta = FALSE; + fetch_data->object_is_stored = FALSE; + fetch_data->requested_ref = (ref != NULL) ? ostree_collection_ref_dup (ref) : NULL; + fetch_data->n_retries_remaining = pull_data->n_network_retries; + + ostree_repo_write_metadata_async (pull_data->repo, OSTREE_OBJECT_TYPE_COMMIT, to_checksum, + to_commit, + pull_data->cancellable, + on_metadata_written, fetch_data); + pull_data->n_outstanding_metadata_write_requests++; + } + } + + n = g_variant_n_children (headers); + pull_data->n_total_deltaparts += n; + + for (guint i = 0; i < n; i++) + { + gboolean have_all = FALSE; + + g_autoptr(GVariant) header = g_variant_get_child_value (headers, i); + g_autoptr(GVariant) csum_v = NULL; + g_autoptr(GVariant) objects = NULL; + g_autoptr(GBytes) inline_part_bytes = NULL; + guint32 version; + guint64 size, usize; + g_variant_get (header, "(u@aytt@ay)", &version, &csum_v, &size, &usize, &objects); + version = maybe_swap_endian_u32 (delta_byteswap, version); + size = maybe_swap_endian_u64 (delta_byteswap, size); + usize = maybe_swap_endian_u64 (delta_byteswap, usize); + + if (version > OSTREE_DELTAPART_VERSION) + return glnx_throw (error, "Delta part has too new version %u", version); + + const guchar *csum = ostree_checksum_bytes_peek_validate (csum_v, error); + if (!csum) + return FALSE; + + if (!_ostree_repo_static_delta_part_have_all_objects (pull_data->repo, + objects, + &have_all, + cancellable, error)) + return FALSE; + + pull_data->total_deltapart_size += size; + pull_data->total_deltapart_usize += usize; + + if (have_all) + { + g_debug ("Have all objects from static delta %s-%s part %u", + from_revision ?: "empty", to_revision, + i); + pull_data->fetched_deltapart_size += size; + pull_data->n_fetched_deltaparts++; + continue; + } + + g_autofree char *deltapart_path = _ostree_get_relative_static_delta_part_path (from_revision, to_revision, i); + + { g_autoptr(GVariant) part_datav = + g_variant_lookup_value (metadata, deltapart_path, G_VARIANT_TYPE ("(yay)")); + + if (part_datav) + inline_part_bytes = g_variant_get_data_as_bytes (part_datav); + } + + if (pull_data->dry_run) + continue; + + FetchStaticDeltaData *fetch_data = g_new0 (FetchStaticDeltaData, 1); + fetch_data->from_revision = g_strdup (from_revision); + fetch_data->to_revision = g_strdup (to_revision); + fetch_data->pull_data = pull_data; + fetch_data->objects = g_variant_ref (objects); + fetch_data->expected_checksum = ostree_checksum_from_bytes_v (csum_v); + fetch_data->size = size; + fetch_data->i = i; + fetch_data->n_retries_remaining = pull_data->n_network_retries; + + if (inline_part_bytes != NULL) + { + g_autoptr(GInputStream) memin = g_memory_input_stream_new_from_bytes (inline_part_bytes); + g_autoptr(GVariant) inline_delta_part = NULL; + + /* For inline parts we are relying on per-commit GPG, so don't bother checksumming. */ + if (!_ostree_static_delta_part_open (memin, inline_part_bytes, + OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM, + NULL, &inline_delta_part, + cancellable, error)) + { + fetch_static_delta_data_free (fetch_data); + return FALSE; + } + + _ostree_static_delta_part_execute_async (pull_data->repo, + fetch_data->objects, + inline_delta_part, + pull_data->cancellable, + on_static_delta_written, + fetch_data); + pull_data->n_outstanding_deltapart_write_requests++; + } + else + { + enqueue_one_static_delta_part_request_s (pull_data, g_steal_pointer (&fetch_data)); + } + } + + /* The free space check is here since at this point we've parsed the delta not + * only the total size of the parts, but also whether or not we already have + * them. TODO: Ideally this free space check would be above, but we'd have to + * walk everything twice and keep track of state. + */ + const guint64 delta_required_blocks = (pull_data->total_deltapart_usize / stvfsbuf.f_bsize); + if (delta_required_blocks > stvfsbuf.f_bfree) + { + g_autofree char *formatted_required = g_format_size (pull_data->total_deltapart_usize); + g_autofree char *formatted_avail = g_format_size (((guint64)stvfsbuf.f_bsize) * stvfsbuf.f_bfree); + return glnx_throw (error, "Delta requires %s free space, but only %s available", + formatted_required, formatted_avail); + } + + return TRUE; +} + +/* + * DELTA_SEARCH_RESULT_UNCHANGED: + * We already have the commit. + * + * DELTA_SEARCH_RESULT_NO_MATCH: + * No deltas were found. + * + * DELTA_SEARCH_RESULT_FROM: + * A regular delta was found, and the "from" revision will be + * set in `from_revision`. + * + * DELTA_SEARCH_RESULT_SCRATCH: + * There is a %NULL → @to_revision delta, also known as + * a "from scratch" delta. + */ +typedef struct { + enum { + DELTA_SEARCH_RESULT_UNCHANGED, + DELTA_SEARCH_RESULT_NO_MATCH, + DELTA_SEARCH_RESULT_FROM, + DELTA_SEARCH_RESULT_SCRATCH, + } result; + char from_revision[OSTREE_SHA256_STRING_LEN+1]; +} DeltaSearchResult; + +/* Loop over the static delta data we got from the summary, + * and find the a delta path (if available) that goes to @to_revision. + * See the enum in `DeltaSearchResult` for available result types. + */ +static gboolean +get_best_static_delta_start_for (OtPullData *pull_data, + const char *to_revision, + DeltaSearchResult *out_result, + GCancellable *cancellable, + GError **error) +{ + /* Array of possible from checksums */ + g_autoptr(GPtrArray) candidates = g_ptr_array_new_with_free_func (g_free); + const char *newest_candidate = NULL; + guint64 newest_candidate_timestamp = 0; + + g_assert (pull_data->summary_deltas_checksums != NULL); + + out_result->result = DELTA_SEARCH_RESULT_NO_MATCH; + out_result->from_revision[0] = '\0'; + + /* First, do we already have this commit completely downloaded? */ + gboolean have_to_rev; + if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_COMMIT, + to_revision, &have_to_rev, + cancellable, error)) + return FALSE; + if (have_to_rev) + { + OstreeRepoCommitState to_rev_state; + if (!ostree_repo_load_commit (pull_data->repo, to_revision, + NULL, &to_rev_state, error)) + return FALSE; + if (!(to_rev_state & OSTREE_REPO_COMMIT_STATE_PARTIAL)) + { + /* We already have this commit, we're done! */ + out_result->result = DELTA_SEARCH_RESULT_UNCHANGED; + return TRUE; /* Early return */ + } + } + + /* Loop over all deltas known from the summary file, + * finding ones which go to to_revision */ + GLNX_HASH_TABLE_FOREACH (pull_data->summary_deltas_checksums, const char*, delta_name) + { + g_autofree char *cur_from_rev = NULL; + g_autofree char *cur_to_rev = NULL; + + /* Gracefully handle corrupted (or malicious) summary files */ + if (!_ostree_parse_delta_name (delta_name, &cur_from_rev, &cur_to_rev, error)) + return FALSE; + + /* Is this the checksum we want? */ + if (strcmp (cur_to_rev, to_revision) != 0) + continue; + + if (cur_from_rev) + { + g_ptr_array_add (candidates, g_steal_pointer (&cur_from_rev)); + } + else + { + /* We note that we have a _SCRATCH delta here, but we'll prefer using + * "from" deltas (obviously, they'll be smaller) where possible if we + * find one below. + */ + out_result->result = DELTA_SEARCH_RESULT_SCRATCH; + } + } + + /* Loop over our candidates, find the newest one */ + for (guint i = 0; i < candidates->len; i++) + { + const char *candidate = candidates->pdata[i]; + guint64 candidate_ts = 0; + g_autoptr(GVariant) commit = NULL; + OstreeRepoCommitState state; + gboolean have_candidate; + + /* Do we have this commit at all? If not, skip it */ + if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_COMMIT, + candidate, &have_candidate, + NULL, error)) + return FALSE; + if (!have_candidate) + continue; + + /* Load it */ + if (!ostree_repo_load_commit (pull_data->repo, candidate, + &commit, &state, error)) + return FALSE; + + /* Ignore partial commits, we can't use them */ + if (state & OSTREE_REPO_COMMIT_STATE_PARTIAL) + continue; + + /* Is it newer? */ + candidate_ts = ostree_commit_get_timestamp (commit); + if (newest_candidate == NULL || + candidate_ts > newest_candidate_timestamp) + { + newest_candidate = candidate; + newest_candidate_timestamp = candidate_ts; + } + } + + if (newest_candidate) + { + out_result->result = DELTA_SEARCH_RESULT_FROM; + memcpy (out_result->from_revision, newest_candidate, OSTREE_SHA256_STRING_LEN+1); + } + return TRUE; +} + +static void +fetch_delta_super_data_free (FetchDeltaSuperData *fetch_data) +{ + g_free (fetch_data->from_revision); + g_free (fetch_data->to_revision); + if (fetch_data->requested_ref) + ostree_collection_ref_free (fetch_data->requested_ref); + g_free (fetch_data); +} + +static void +set_required_deltas_error (GError **error, + const char *from_revision, + const char *to_revision) +{ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Static deltas required, but none found for %s to %s", + from_revision, to_revision); +} + +static void +on_superblock_fetched (GObject *src, + GAsyncResult *res, + gpointer data) + +{ + FetchDeltaSuperData *fetch_data = data; + OtPullData *pull_data = fetch_data->pull_data; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + g_autoptr(GBytes) delta_superblock_data = NULL; + const char *from_revision = fetch_data->from_revision; + const char *to_revision = fetch_data->to_revision; + + if (!_ostree_fetcher_request_to_membuf_finish ((OstreeFetcher*)src, + res, + &delta_superblock_data, + error)) + { + if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + goto out; + g_clear_error (&local_error); + + if (pull_data->require_static_deltas) + { + set_required_deltas_error (error, from_revision, to_revision); + goto out; + } + + queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, fetch_data->requested_ref); + } + else + { + g_autoptr(GVariant) delta_superblock = NULL; + g_autofree gchar *delta = g_strconcat (from_revision ?: "", from_revision ? "-" : "", to_revision, NULL); + const guchar *expected_summary_digest = g_hash_table_lookup (pull_data->summary_deltas_checksums, delta); + guint8 actual_summary_digest[OSTREE_SHA256_DIGEST_LEN]; + + g_auto(OtChecksum) hasher = { 0, }; + ot_checksum_init (&hasher); + ot_checksum_update_bytes (&hasher, delta_superblock_data); + ot_checksum_get_digest (&hasher, actual_summary_digest, sizeof (actual_summary_digest)); + +#ifndef OSTREE_DISABLE_GPGME + /* At this point we've GPG verified the data, so in theory + * could trust that they provided the right data, but let's + * make this a hard error. + */ + if (pull_data->gpg_verify_summary && !expected_summary_digest) + { + g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, + "GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)"); + goto out; + } +#endif /* OSTREE_DISABLE_GPGME */ + + if (expected_summary_digest && memcmp (expected_summary_digest, actual_summary_digest, sizeof (actual_summary_digest))) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid checksum for static delta %s", delta); + goto out; + } + + delta_superblock = g_variant_ref_sink (g_variant_new_from_bytes ((GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT, + delta_superblock_data, FALSE)); + + g_ptr_array_add (pull_data->static_delta_superblocks, g_variant_ref (delta_superblock)); + if (!process_one_static_delta (pull_data, from_revision, to_revision, delta_superblock, fetch_data->requested_ref, + pull_data->cancellable, error)) + goto out; + } + + out: + g_assert (pull_data->n_outstanding_metadata_fetches > 0); + pull_data->n_outstanding_metadata_fetches--; + + if (local_error == NULL) + pull_data->n_fetched_metadata++; + + if (_ostree_fetcher_should_retry_request (local_error, fetch_data->n_retries_remaining--)) + enqueue_one_static_delta_superblock_request_s (pull_data, g_steal_pointer (&fetch_data)); + else + check_outstanding_requests_handle_error (pull_data, &local_error); + + g_clear_pointer (&fetch_data, fetch_delta_super_data_free); +} + +static void +start_fetch_delta_superblock (OtPullData *pull_data, + FetchDeltaSuperData *fetch_data) +{ + g_autofree char *delta_name = + _ostree_get_relative_static_delta_superblock_path (fetch_data->from_revision, + fetch_data->to_revision); + _ostree_fetcher_request_to_membuf (pull_data->fetcher, + pull_data->content_mirrorlist, + delta_name, OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT, + OSTREE_MAX_METADATA_SIZE, + 0, pull_data->cancellable, + on_superblock_fetched, + g_steal_pointer (&fetch_data)); + pull_data->n_outstanding_metadata_fetches++; + pull_data->n_requested_metadata++; +} + +static void +enqueue_one_static_delta_superblock_request_s (OtPullData *pull_data, + FetchDeltaSuperData *fetch_data) +{ + if (fetcher_queue_is_full (pull_data)) + { + g_debug ("queuing fetch of static delta superblock %s-%s", + fetch_data->from_revision ?: "empty", + fetch_data->to_revision); + + g_hash_table_add (pull_data->pending_fetch_delta_superblocks, + g_steal_pointer (&fetch_data)); + } + else + { + start_fetch_delta_superblock (pull_data, g_steal_pointer (&fetch_data)); + } +} + +/* Start a request for a static delta */ +static void +enqueue_one_static_delta_superblock_request (OtPullData *pull_data, + const char *from_revision, + const char *to_revision, + const OstreeCollectionRef *ref) +{ + FetchDeltaSuperData *fdata = g_new0(FetchDeltaSuperData, 1); + fdata->pull_data = pull_data; + fdata->from_revision = g_strdup (from_revision); + fdata->to_revision = g_strdup (to_revision); + fdata->requested_ref = (ref != NULL) ? ostree_collection_ref_dup (ref) : NULL; + fdata->n_retries_remaining = pull_data->n_network_retries; + + enqueue_one_static_delta_superblock_request_s (pull_data, g_steal_pointer (&fdata)); +} + +static gboolean +validate_variant_is_csum (GVariant *csum, + GError **error) +{ + if (!g_variant_is_of_type (csum, G_VARIANT_TYPE ("ay"))) + return glnx_throw (error, "Invalid checksum variant of type '%s', expected 'ay'", + g_variant_get_type_string (csum)); + + return ostree_validate_structureof_csum_v (csum, error); +} + +/* Load the summary from the cache if the provided .sig file is the same as the + cached version. */ +static gboolean +_ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self, + const char *remote, + GBytes *summary_sig, + GBytes **summary, + GCancellable *cancellable, + GError **error) +{ + if (self->cache_dir_fd == -1) + return TRUE; + + const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); + glnx_autofd int prev_fd = -1; + if (!ot_openat_ignore_enoent (self->cache_dir_fd, summary_cache_sig_file, &prev_fd, error)) + return FALSE; + if (prev_fd < 0) + return TRUE; /* Note early return */ + + g_autoptr(GBytes) old_sig_contents = ot_fd_readall_or_mmap (prev_fd, 0, error); + if (!old_sig_contents) + return FALSE; + + if (g_bytes_compare (old_sig_contents, summary_sig) == 0) + { + const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote); + glnx_autofd int summary_fd = -1; + GBytes *summary_data; + + + summary_fd = openat (self->cache_dir_fd, summary_cache_file, O_CLOEXEC | O_RDONLY); + if (summary_fd < 0) + { + if (errno == ENOENT) + { + (void) unlinkat (self->cache_dir_fd, summary_cache_sig_file, 0); + return TRUE; /* Note early return */ + } + + return glnx_throw_errno_prefix (error, "openat(%s)", summary_cache_file); + } + + summary_data = glnx_fd_readall_bytes (summary_fd, cancellable, error); + if (!summary_data) + return FALSE; + *summary = summary_data; + } + return TRUE; +} + +/* Replace the current summary+signature with new versions */ +static gboolean +_ostree_repo_cache_summary (OstreeRepo *self, + const char *remote, + GBytes *summary, + GBytes *summary_sig, + GCancellable *cancellable, + GError **error) +{ + if (self->cache_dir_fd == -1) + return TRUE; + + if (!glnx_shutil_mkdir_p_at (self->cache_dir_fd, _OSTREE_SUMMARY_CACHE_DIR, DEFAULT_DIRECTORY_MODE, cancellable, error)) + return FALSE; + + const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote); + if (!glnx_file_replace_contents_at (self->cache_dir_fd, + summary_cache_file, + g_bytes_get_data (summary, NULL), + g_bytes_get_size (summary), + self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW, + cancellable, error)) + return FALSE; + + const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); + if (!glnx_file_replace_contents_at (self->cache_dir_fd, + summary_cache_sig_file, + g_bytes_get_data (summary_sig, NULL), + g_bytes_get_size (summary_sig), + self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW, + cancellable, error)) + return FALSE; + + return TRUE; +} + +static OstreeFetcher * +_ostree_repo_remote_new_fetcher (OstreeRepo *self, + const char *remote_name, + gboolean gzip, + OstreeFetcherSecurityState *out_state, + GError **error) +{ + OstreeFetcher *fetcher = NULL; + OstreeFetcherConfigFlags fetcher_flags = 0; + gboolean tls_permissive = FALSE; + OstreeFetcherSecurityState ret_state = OSTREE_FETCHER_SECURITY_STATE_TLS; + gboolean success = FALSE; + + g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); + g_return_val_if_fail (remote_name != NULL, NULL); + + if (!ostree_repo_get_remote_boolean_option (self, remote_name, + "tls-permissive", FALSE, + &tls_permissive, error)) + goto out; + + if (tls_permissive) + { + fetcher_flags |= OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE; + ret_state = OSTREE_FETCHER_SECURITY_STATE_INSECURE; + } + + if (gzip) + fetcher_flags |= OSTREE_FETCHER_FLAGS_TRANSFER_GZIP; + + { gboolean http2_default = TRUE; +#ifndef BUILDOPT_HTTP2 + http2_default = FALSE; +#endif + gboolean http2; + + if (!ostree_repo_get_remote_boolean_option (self, remote_name, + "http2", http2_default, + &http2, error)) + goto out; + if (!http2) + fetcher_flags |= OSTREE_FETCHER_FLAGS_DISABLE_HTTP2; + } + + fetcher = _ostree_fetcher_new (self->tmp_dir_fd, remote_name, fetcher_flags); + + { + g_autofree char *tls_client_cert_path = NULL; + g_autofree char *tls_client_key_path = NULL; + + if (!ostree_repo_get_remote_option (self, remote_name, + "tls-client-cert-path", NULL, + &tls_client_cert_path, error)) + goto out; + if (!ostree_repo_get_remote_option (self, remote_name, + "tls-client-key-path", NULL, + &tls_client_key_path, error)) + goto out; + + if ((tls_client_cert_path != NULL) != (tls_client_key_path != NULL)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Remote \"%s\" must specify both " + "\"tls-client-cert-path\" and \"tls-client-key-path\"", + remote_name); + goto out; + } + else if (tls_client_cert_path != NULL) + { + _ostree_fetcher_set_client_cert (fetcher, tls_client_cert_path, tls_client_key_path); + } + } + + { + g_autofree char *tls_ca_path = NULL; + + if (!ostree_repo_get_remote_option (self, remote_name, + "tls-ca-path", NULL, + &tls_ca_path, error)) + goto out; + + if (tls_ca_path != NULL) + { + _ostree_fetcher_set_tls_database (fetcher, tls_ca_path); + + /* Don't change if it's already _INSECURE */ + if (ret_state == OSTREE_FETCHER_SECURITY_STATE_TLS) + ret_state = OSTREE_FETCHER_SECURITY_STATE_CA_PINNED; + } + } + + { + g_autofree char *http_proxy = NULL; + + if (!ostree_repo_get_remote_option (self, remote_name, + "proxy", NULL, + &http_proxy, error)) + goto out; + + if (http_proxy != NULL && http_proxy[0] != '\0') + _ostree_fetcher_set_proxy (fetcher, http_proxy); + } + + if (!_ostree_repo_remote_name_is_file (remote_name)) + { + g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name); + /* TODO; port away from this; a bit hard since both libsoup and libcurl + * expect a file. Doing ot_fdrel_to_gfile() works for now though. + */ + GFile*repo_path = ostree_repo_get_path (self); + g_autofree char *jar_path = + g_build_filename (gs_file_get_path_cached (repo_path), cookie_file, NULL); + + if (g_file_test (jar_path, G_FILE_TEST_IS_REGULAR)) + _ostree_fetcher_set_cookie_jar (fetcher, jar_path); + } + + success = TRUE; + +out: + if (!success) + g_clear_object (&fetcher); + if (out_state) + *out_state = ret_state; + + return fetcher; +} + +static gboolean +_ostree_preload_metadata_file (OstreeRepo *self, + OstreeFetcher *fetcher, + GPtrArray *mirrorlist, + const char *filename, + gboolean is_metalink, + guint n_network_retries, + GBytes **out_bytes, + GCancellable *cancellable, + GError **error) +{ + if (is_metalink) + { + GError *local_error = NULL; + + /* the metalink uri is buried in the mirrorlist as the first (and only) + * element */ + g_autoptr(OstreeMetalink) metalink = + _ostree_metalink_new (fetcher, filename, + OSTREE_MAX_METADATA_SIZE, + mirrorlist->pdata[0], n_network_retries); + + _ostree_metalink_request_sync (metalink, NULL, out_bytes, + cancellable, &local_error); + + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&local_error); + *out_bytes = NULL; + } + else if (local_error != NULL) + { + g_propagate_error (error, local_error); + return FALSE; + } + + return TRUE; + } + else + { + return _ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist, filename, + OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT, + n_network_retries, + out_bytes, OSTREE_MAX_METADATA_SIZE, + cancellable, error); + } +} + +static gboolean +fetch_mirrorlist (OstreeFetcher *fetcher, + const char *mirrorlist_url, + guint n_network_retries, + GPtrArray **out_mirrorlist, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GPtrArray) ret_mirrorlist = + g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free); + + g_autoptr(OstreeFetcherURI) mirrorlist = _ostree_fetcher_uri_parse (mirrorlist_url, error); + if (!mirrorlist) + return FALSE; + + g_autofree char *contents = NULL; + if (!fetch_uri_contents_utf8_sync (fetcher, mirrorlist, n_network_retries, + &contents, cancellable, error)) + return glnx_prefix_error (error, "While fetching mirrorlist '%s'", + mirrorlist_url); + + /* go through each mirror in mirrorlist and do a quick sanity check that it + * works so that we don't waste the fetcher's time when it goes through them + * */ + g_auto(GStrv) lines = g_strsplit (contents, "\n", -1); + g_debug ("Scanning mirrorlist from '%s'", mirrorlist_url); + for (char **iter = lines; iter && *iter; iter++) + { + const char *mirror_uri_str = *iter; + g_autoptr(OstreeFetcherURI) mirror_uri = NULL; + g_autofree char *scheme = NULL; + + /* let's be nice and support empty lines and comments */ + if (*mirror_uri_str == '\0' || *mirror_uri_str == '#') + continue; + + mirror_uri = _ostree_fetcher_uri_parse (mirror_uri_str, NULL); + if (!mirror_uri) + { + g_debug ("Can't parse mirrorlist line '%s'", mirror_uri_str); + continue; + } + + scheme = _ostree_fetcher_uri_get_scheme (mirror_uri); + if (!(g_str_equal (scheme, "http") || (g_str_equal (scheme, "https")))) + { + /* let's not support mirrorlists that contain non-http based URIs for + * now (e.g. local URIs) -- we need to think about if and how we want + * to support this since we set up things differently depending on + * whether we're pulling locally or not */ + g_debug ("Ignoring non-http/s mirrorlist entry '%s'", mirror_uri_str); + continue; + } + + /* We keep sanity checking until we hit a working mirror; there's no need + * to waste resources checking the remaining ones. At the same time, + * guaranteeing that the first mirror in the list works saves the fetcher + * time from always iterating through a few bad first mirrors. */ + if (ret_mirrorlist->len == 0) + { + GError *local_error = NULL; + g_autoptr(OstreeFetcherURI) config_uri = _ostree_fetcher_uri_new_subpath (mirror_uri, "config"); + + if (fetch_uri_contents_utf8_sync (fetcher, config_uri, n_network_retries, + NULL, cancellable, &local_error)) + g_ptr_array_add (ret_mirrorlist, g_steal_pointer (&mirror_uri)); + else + { + g_debug ("Failed to fetch config from mirror '%s': %s", + mirror_uri_str, local_error->message); + g_clear_error (&local_error); + } + } + else + { + g_ptr_array_add (ret_mirrorlist, g_steal_pointer (&mirror_uri)); + } + } + + if (ret_mirrorlist->len == 0) + return glnx_throw (error, "No valid mirrors were found in mirrorlist '%s'", + mirrorlist_url); + + *out_mirrorlist = g_steal_pointer (&ret_mirrorlist); + return TRUE; +} + +static gboolean +repo_remote_fetch_summary (OstreeRepo *self, + const char *name, + const char *metalink_url_string, + GVariant *options, + GBytes **out_summary, + GBytes **out_signatures, + gboolean *out_from_cache, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeFetcher) fetcher = NULL; + g_autoptr(GMainContext) mainctx = NULL; + gboolean ret = FALSE; + gboolean from_cache = FALSE; + const char *url_override = NULL; + g_autoptr(GVariant) extra_headers = NULL; + g_autoptr(GPtrArray) mirrorlist = NULL; + const char *append_user_agent = NULL; + guint n_network_retries = DEFAULT_N_NETWORK_RETRIES; + + if (options) + { + (void) g_variant_lookup (options, "override-url", "&s", &url_override); + (void) g_variant_lookup (options, "http-headers", "@a(ss)", &extra_headers); + (void) g_variant_lookup (options, "append-user-agent", "&s", &append_user_agent); + (void) g_variant_lookup (options, "n-network-retries", "&u", &n_network_retries); + } + + mainctx = g_main_context_new (); + g_main_context_push_thread_default (mainctx); + + fetcher = _ostree_repo_remote_new_fetcher (self, name, TRUE, NULL, error); + if (fetcher == NULL) + goto out; + + if (extra_headers) + _ostree_fetcher_set_extra_headers (fetcher, extra_headers); + + if (append_user_agent) + _ostree_fetcher_set_extra_user_agent (fetcher, append_user_agent); + + { + g_autofree char *url_string = NULL; + if (metalink_url_string) + url_string = g_strdup (metalink_url_string); + else if (url_override) + url_string = g_strdup (url_override); + else if (!ostree_repo_remote_get_url (self, name, &url_string, error)) + goto out; + + if (metalink_url_string == NULL && + g_str_has_prefix (url_string, "mirrorlist=")) + { + if (!fetch_mirrorlist (fetcher, url_string + strlen ("mirrorlist="), + n_network_retries, &mirrorlist, cancellable, error)) + goto out; + } + else + { + g_autoptr(OstreeFetcherURI) uri = _ostree_fetcher_uri_parse (url_string, error); + + if (!uri) + goto out; + + mirrorlist = + g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free); + g_ptr_array_add (mirrorlist, g_steal_pointer (&uri)); + } + } + + /* FIXME: Send the ETag from the cache with the request for summary.sig to + * avoid downloading summary.sig unnecessarily. This won’t normally provide + * any benefits (but won’t do any harm) since summary.sig is typically 500B + * in size. But if a repository has multiple keys, the signature file will + * grow and this optimisation may be useful. */ + if (!_ostree_preload_metadata_file (self, + fetcher, + mirrorlist, + "summary.sig", + metalink_url_string ? TRUE : FALSE, + n_network_retries, + out_signatures, + cancellable, + error)) + goto out; + + if (*out_signatures) + { + if (!_ostree_repo_load_cache_summary_if_same_sig (self, + name, + *out_signatures, + out_summary, + cancellable, + error)) + goto out; + } + + if (*out_summary) + from_cache = TRUE; + else + { + if (!_ostree_preload_metadata_file (self, + fetcher, + mirrorlist, + "summary", + metalink_url_string ? TRUE : FALSE, + n_network_retries, + out_summary, + cancellable, + error)) + goto out; + } + + ret = TRUE; + + out: + if (mainctx) + g_main_context_pop_thread_default (mainctx); + + *out_from_cache = from_cache; + return ret; +} + +/* Create the fetcher by unioning options from the remote config, plus + * any options specific to this pull (such as extra headers). + */ +static gboolean +reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, + GError **error) +{ + g_clear_object (&pull_data->fetcher); + pull_data->fetcher = _ostree_repo_remote_new_fetcher (pull_data->repo, remote_name, FALSE, + &pull_data->fetcher_security_state, + error); + if (pull_data->fetcher == NULL) + return FALSE; + + if (pull_data->extra_headers) + _ostree_fetcher_set_extra_headers (pull_data->fetcher, pull_data->extra_headers); + + if (pull_data->append_user_agent) + _ostree_fetcher_set_extra_user_agent (pull_data->fetcher, pull_data->append_user_agent); + + return TRUE; +} + +/* + * initiate_request: + * @ref: Optional ref name and collection ID + * @to_revision: Target commit revision we want to fetch + * + * Start a request for either a ref or a commit. In the + * ref case, we know both the name and the target commit. + * + * This function primarily handles the semantics around + * `disable_static_deltas` and `require_static_deltas`. + */ +static gboolean +initiate_request (OtPullData *pull_data, + const OstreeCollectionRef *ref, + const char *to_revision, + GError **error) +{ + g_autofree char *delta_from_revision = NULL; + + /* Are deltas disabled? OK, just start an object fetch and be done */ + if (pull_data->disable_static_deltas) + { + queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, ref); + return TRUE; + } + + /* If doing a delta from a ref, look up the from-revision, since we need it + * on most paths below. */ + if (ref != NULL) + { + g_autofree char *refspec = NULL; + if (pull_data->remote_name != NULL) + refspec = g_strdup_printf ("%s:%s", pull_data->remote_name, ref->ref_name); + if (!ostree_repo_resolve_rev (pull_data->repo, + refspec ?: ref->ref_name, TRUE, + &delta_from_revision, error)) + return FALSE; + } + + /* If we have a summary, we can use the newer logic */ + if (pull_data->summary) + { + DeltaSearchResult deltares; + + /* Look for a delta to @to_revision in the summary data */ + if (!get_best_static_delta_start_for (pull_data, to_revision, &deltares, + pull_data->cancellable, error)) + return FALSE; + + switch (deltares.result) + { + case DELTA_SEARCH_RESULT_NO_MATCH: + { + if (pull_data->require_static_deltas) /* No deltas found; are they required? */ + { + set_required_deltas_error (error, (ref != NULL) ? ref->ref_name : "", to_revision); + return FALSE; + } + else /* No deltas, fall back to object fetches. */ + queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, ref); + } + break; + case DELTA_SEARCH_RESULT_FROM: + enqueue_one_static_delta_superblock_request (pull_data, deltares.from_revision, to_revision, ref); + break; + case DELTA_SEARCH_RESULT_SCRATCH: + { + /* If a from-scratch delta is available, we don’t want to use it if + * the ref already exists locally, since we are likely only a few + * commits out of date; so doing an object pull is likely more + * bandwidth efficient. */ + if (delta_from_revision != NULL) + queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, ref); + else + enqueue_one_static_delta_superblock_request (pull_data, NULL, to_revision, ref); + } + break; + case DELTA_SEARCH_RESULT_UNCHANGED: + { + /* If we already have the commit, here things get a little special; we've historically + * fetched detached metadata, so let's keep doing that. But in the --require-static-deltas + * path, we don't, under the assumption the user wants as little network traffic as + * possible. + */ + if (pull_data->require_static_deltas) + break; + else + queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, ref); + } + } + } + else if (ref != NULL) + { + /* Are we doing a delta via a ref? In that case we can fall back to the older + * logic of just using the current tip of the ref as a delta FROM source. */ + + /* Determine whether the from revision we have is partial; this + * can happen if e.g. one uses `ostree pull --commit-metadata-only`. + * This mirrors the logic in get_best_static_delta_start_for(). + */ + if (delta_from_revision) + { + OstreeRepoCommitState from_commitstate; + + if (!ostree_repo_load_commit (pull_data->repo, delta_from_revision, NULL, + &from_commitstate, error)) + return FALSE; + + /* Was it partial? Then we can't use it. */ + if (commitstate_is_partial (pull_data, from_commitstate)) + g_clear_pointer (&delta_from_revision, g_free); + } + + /* If the current ref is the same, we don't do a delta request, just a + * scan. Otherise, use the previous commit if available, or a scratch + * delta. + */ + if (delta_from_revision && g_str_equal (delta_from_revision, to_revision)) + queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0, ref); + else + enqueue_one_static_delta_superblock_request (pull_data, delta_from_revision ?: NULL, to_revision, ref); + } + else + { + /* Legacy path without a summary file - let's try a scratch delta, if that + * doesn't work, it'll drop down to object requests. + */ + enqueue_one_static_delta_superblock_request (pull_data, NULL, to_revision, NULL); + } + + return TRUE; +} + +/* ------------------------------------------------------------------------------------------ + * Below is the libsoup-invariant API; these should match + * the stub functions in the #else clause + * ------------------------------------------------------------------------------------------ + */ + +/** + * ostree_repo_pull_with_options: + * @self: Repo + * @remote_name_or_baseurl: Name of remote or file:// url + * @options: A GVariant a{sv} with an extensible set of flags. + * @progress: (allow-none): Progress + * @cancellable: Cancellable + * @error: Error + * + * Like ostree_repo_pull(), but supports an extensible set of flags. + * The following are currently defined: + * + * * refs (as): Array of string refs + * * collection-refs (a(sss)): Array of (collection ID, ref name, checksum) tuples to pull; + * mutually exclusive with `refs` and `override-commit-ids`. Checksums may be the empty + * string to pull the latest commit for that ref + * * flags (i): An instance of #OstreeRepoPullFlags + * * subdir (s): Pull just this subdirectory + * * subdirs (as): Pull just these subdirectories + * * override-remote-name (s): If local, add this remote to refspec + * * gpg-verify (b): GPG verify commits + * * gpg-verify-summary (b): GPG verify summary + * * disable-sign-verify (b): Disable signapi verification of commits + * * disable-sign-verify-summary (b): Disable signapi verification of the summary + * * depth (i): How far in the history to traverse; default is 0, -1 means infinite + * * per-object-fsync (b): Perform disk writes more slowly, avoiding a single large I/O sync + * * disable-static-deltas (b): Do not use static deltas + * * require-static-deltas (b): Require static deltas + * * override-commit-ids (as): Array of specific commit IDs to fetch for refs + * * timestamp-check (b): Verify commit timestamps are newer than current (when pulling via ref); Since: 2017.11 + * * timestamp-check-from-rev (s): Verify that all fetched commit timestamps are newer than timestamp of given rev; Since: 2020.4 + * * metadata-size-restriction (t): Restrict metadata objects to a maximum number of bytes; 0 to disable. Since: 2018.9 + * * dry-run (b): Only print information on what will be downloaded (requires static deltas) + * * override-url (s): Fetch objects from this URL if remote specifies no metalink in options + * * inherit-transaction (b): Don't initiate, finish or abort a transaction, useful to do multiple pulls in one transaction. + * * http-headers (a(ss)): Additional headers to add to all HTTP requests + * * update-frequency (u): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid + * * localcache-repos (as): File paths for local repos to use as caches when doing remote fetches + * * append-user-agent (s): Additional string to append to the user agent + * * n-network-retries (u): Number of times to retry each download on receiving + * a transient network error, such as a socket timeout; default is 5, 0 + * means return errors without retrying. Since: 2018.6 + * * ref-keyring-map (a(sss)): Array of (collection ID, ref name, keyring + * remote name) tuples specifying which remote's keyring should be used when + * doing GPG verification of each collection-ref. This is useful to prevent a + * remote from serving malicious updates to refs which did not originate from + * it. This can be a subset or superset of the refs being pulled; any ref + * not being pulled will be ignored and any ref without a keyring remote + * will be verified with the keyring of the remote being pulled from. + * Since: 2019.2 + */ +gboolean +ostree_repo_pull_with_options (OstreeRepo *self, + const char *remote_name_or_baseurl, + GVariant *options, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GBytes) bytes_summary = NULL; + g_autofree char *metalink_url_str = NULL; + g_autoptr(GHashTable) requested_refs_to_fetch = NULL; /* (element-type OstreeCollectionRef utf8) */ + g_autoptr(GHashTable) commits_to_fetch = NULL; + g_autofree char *remote_mode_str = NULL; + g_autoptr(OstreeMetalink) metalink = NULL; + OtPullData pull_data_real = { 0, }; + OtPullData *pull_data = &pull_data_real; + GKeyFile *remote_config = NULL; + char **configured_branches = NULL; + guint64 bytes_transferred; + guint64 end_time; + guint update_frequency = 0; + OstreeRepoPullFlags flags = 0; + const char *dir_to_pull = NULL; + g_autofree char **dirs_to_pull = NULL; + g_autofree char **refs_to_fetch = NULL; + g_autoptr(GVariantIter) collection_refs_iter = NULL; + g_autofree char **override_commit_ids = NULL; + g_autoptr(GSource) update_timeout = NULL; + gboolean opt_per_object_fsync = FALSE; + gboolean opt_gpg_verify_set = FALSE; + gboolean opt_gpg_verify_summary_set = FALSE; + gboolean opt_collection_refs_set = FALSE; + gboolean opt_n_network_retries_set = FALSE; + gboolean opt_ref_keyring_map_set = FALSE; + gboolean disable_sign_verify = FALSE; + gboolean disable_sign_verify_summary = FALSE; + const char *main_collection_id = NULL; + const char *url_override = NULL; + gboolean inherit_transaction = FALSE; + g_autoptr(GHashTable) updated_requested_refs_to_fetch = NULL; /* (element-type OstreeCollectionRef utf8) */ + int i; + g_autofree char **opt_localcache_repos = NULL; + g_autoptr(GVariantIter) ref_keyring_map_iter = NULL; + /* If refs or collection-refs has exactly one value, this will point to that + * value, otherwise NULL. Used for logging. + */ + const char *the_ref_to_fetch = NULL; + OstreeRepoTransactionStats tstats = { 0, }; + + /* Default */ + pull_data->max_metadata_size = OSTREE_MAX_METADATA_SIZE; + + if (options) + { + int flags_i = OSTREE_REPO_PULL_FLAGS_NONE; + (void) g_variant_lookup (options, "refs", "^a&s", &refs_to_fetch); + opt_collection_refs_set = + g_variant_lookup (options, "collection-refs", "a(sss)", &collection_refs_iter); + (void) g_variant_lookup (options, "flags", "i", &flags_i); + /* Reduce risk of issues if enum happens to be 64 bit for some reason */ + flags = flags_i; + (void) g_variant_lookup (options, "subdir", "&s", &dir_to_pull); + (void) g_variant_lookup (options, "subdirs", "^a&s", &dirs_to_pull); + (void) g_variant_lookup (options, "override-remote-name", "s", &pull_data->remote_refspec_name); + opt_gpg_verify_set = + g_variant_lookup (options, "gpg-verify", "b", &pull_data->gpg_verify); + opt_gpg_verify_summary_set = + g_variant_lookup (options, "gpg-verify-summary", "b", &pull_data->gpg_verify_summary); + g_variant_lookup (options, "disable-sign-verify", "b", &disable_sign_verify); + g_variant_lookup (options, "disable-sign-verify-summary", "b", &disable_sign_verify_summary); + (void) g_variant_lookup (options, "depth", "i", &pull_data->maxdepth); + (void) g_variant_lookup (options, "disable-static-deltas", "b", &pull_data->disable_static_deltas); + (void) g_variant_lookup (options, "require-static-deltas", "b", &pull_data->require_static_deltas); + (void) g_variant_lookup (options, "override-commit-ids", "^a&s", &override_commit_ids); + (void) g_variant_lookup (options, "dry-run", "b", &pull_data->dry_run); + (void) g_variant_lookup (options, "per-object-fsync", "b", &opt_per_object_fsync); + (void) g_variant_lookup (options, "override-url", "&s", &url_override); + (void) g_variant_lookup (options, "inherit-transaction", "b", &inherit_transaction); + (void) g_variant_lookup (options, "http-headers", "@a(ss)", &pull_data->extra_headers); + (void) g_variant_lookup (options, "update-frequency", "u", &update_frequency); + (void) g_variant_lookup (options, "localcache-repos", "^a&s", &opt_localcache_repos); + (void) g_variant_lookup (options, "timestamp-check", "b", &pull_data->timestamp_check); + (void) g_variant_lookup (options, "timestamp-check-from-rev", "s", &pull_data->timestamp_check_from_rev); + (void) g_variant_lookup (options, "max-metadata-size", "t", &pull_data->max_metadata_size); + (void) g_variant_lookup (options, "append-user-agent", "s", &pull_data->append_user_agent); + opt_n_network_retries_set = + g_variant_lookup (options, "n-network-retries", "u", &pull_data->n_network_retries); + opt_ref_keyring_map_set = + g_variant_lookup (options, "ref-keyring-map", "a(sss)", &ref_keyring_map_iter); + + if (pull_data->remote_refspec_name != NULL) + pull_data->remote_name = g_strdup (pull_data->remote_refspec_name); + } + +#ifdef OSTREE_DISABLE_GPGME + /* Explicitly fail here if gpg verification is requested and we have no GPG support */ + if (pull_data->gpg_verify || pull_data->gpg_verify_summary) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "'%s': GPG feature is disabled at build time", + __FUNCTION__); + goto out; + } +#endif + + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (pull_data->maxdepth >= -1, FALSE); + g_return_val_if_fail (!pull_data->timestamp_check || pull_data->maxdepth == 0, FALSE); + g_return_val_if_fail (!opt_collection_refs_set || + (refs_to_fetch == NULL && override_commit_ids == NULL), FALSE); + if (refs_to_fetch && override_commit_ids) + g_return_val_if_fail (g_strv_length (refs_to_fetch) == g_strv_length (override_commit_ids), FALSE); + + if (dir_to_pull) + g_return_val_if_fail (dir_to_pull[0] == '/', FALSE); + + for (i = 0; dirs_to_pull != NULL && dirs_to_pull[i] != NULL; i++) + g_return_val_if_fail (dirs_to_pull[i][0] == '/', FALSE); + + g_return_val_if_fail (!(pull_data->disable_static_deltas && pull_data->require_static_deltas), FALSE); + + /* We only do dry runs with static deltas, because we don't really have any + * in-advance information for bare fetches. + */ + g_return_val_if_fail (!pull_data->dry_run || pull_data->require_static_deltas, FALSE); + + pull_data->is_mirror = (flags & OSTREE_REPO_PULL_FLAGS_MIRROR) > 0; + pull_data->is_commit_only = (flags & OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY) > 0; + /* See our processing of OSTREE_REPO_PULL_FLAGS_UNTRUSTED below */ + if ((flags & OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES) > 0) + pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY; + pull_data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + if (error) + pull_data->async_error = &pull_data->cached_async_error; + else + pull_data->async_error = NULL; + + /* Note we're using the thread default (or global) context here, so it may outlive the + * OtPullData object if there's another ref on it. Thus, always detach/destroy sources + * local to the `ostree_repo_pull*` operation rather than trying to transfer ownership. */ + pull_data->main_context = g_main_context_ref_thread_default (); + pull_data->flags = flags; + + /* TODO: Avoid mutating the repo object */ + if (opt_per_object_fsync) + self->per_object_fsync = TRUE; + + if (!opt_n_network_retries_set) + pull_data->n_network_retries = DEFAULT_N_NETWORK_RETRIES; + + pull_data->repo = self; + pull_data->progress = progress; + + pull_data->expected_commit_sizes = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)g_free); + pull_data->commit_to_depth = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, + NULL); + pull_data->summary_deltas_checksums = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)g_free); + pull_data->ref_original_commits = g_hash_table_new_full (ostree_collection_ref_hash, ostree_collection_ref_equal, + (GDestroyNotify)NULL, + (GDestroyNotify)g_free); + pull_data->verified_commits = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, NULL); + pull_data->signapi_verified_commits = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, NULL); + pull_data->ref_keyring_map = g_hash_table_new_full (ostree_collection_ref_hash, ostree_collection_ref_equal, + (GDestroyNotify)ostree_collection_ref_free, (GDestroyNotify)g_free); + pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, + (GDestroyNotify)g_variant_unref, NULL); + pull_data->fetched_detached_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, (GDestroyNotify)variant_or_null_unref); + pull_data->requested_content = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, NULL); + pull_data->requested_fallback_content = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, NULL); + pull_data->requested_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, + (GDestroyNotify)g_variant_unref, NULL); + pull_data->pending_fetch_content = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify)g_free, + (GDestroyNotify)fetch_object_data_free); + pull_data->pending_fetch_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, + (GDestroyNotify)g_variant_unref, + (GDestroyNotify)fetch_object_data_free); + pull_data->pending_fetch_delta_superblocks = g_hash_table_new_full (NULL, NULL, (GDestroyNotify) fetch_delta_super_data_free, NULL); + pull_data->pending_fetch_deltaparts = g_hash_table_new_full (NULL, NULL, (GDestroyNotify)fetch_static_delta_data_free, NULL); + + if (opt_localcache_repos && *opt_localcache_repos) + { + pull_data->localcache_repos = g_ptr_array_new_with_free_func (g_object_unref); + for (char **it = opt_localcache_repos; it && *it; it++) + { + const char *localcache_path = *it; + g_autoptr(GFile) localcache_file = g_file_new_for_path (localcache_path); + g_autoptr(OstreeRepo) cacherepo = ostree_repo_new (localcache_file); + if (!ostree_repo_open (cacherepo, cancellable, error)) + goto out; + g_ptr_array_add (pull_data->localcache_repos, g_steal_pointer (&cacherepo)); + } + } + + if (dir_to_pull != NULL || dirs_to_pull != NULL) + { + pull_data->dirs = g_ptr_array_new_with_free_func (g_free); + if (dir_to_pull != NULL) + g_ptr_array_add (pull_data->dirs, g_strdup (dir_to_pull)); + + if (dirs_to_pull != NULL) + { + for (i = 0; dirs_to_pull[i] != NULL; i++) + g_ptr_array_add (pull_data->dirs, g_strdup (dirs_to_pull[i])); + } + } + + g_queue_init (&pull_data->scan_object_queue); + + pull_data->start_time = g_get_monotonic_time (); + + if (_ostree_repo_remote_name_is_file (remote_name_or_baseurl)) + { + /* For compatibility with pull-local, don't gpg verify local + * pulls by default. + */ + if ((pull_data->gpg_verify || + pull_data->gpg_verify_summary + ) && + pull_data->remote_name == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Must specify remote name to enable gpg verification"); + goto out; + } + } + else + { + g_autofree char *unconfigured_state = NULL; + + g_free (pull_data->remote_name); + pull_data->remote_name = g_strdup (remote_name_or_baseurl); + + /* Fetch GPG verification settings from remote if it wasn't already + * explicitly set in the options. */ + if (!opt_gpg_verify_set) + if (!ostree_repo_remote_get_gpg_verify (self, pull_data->remote_name, + &pull_data->gpg_verify, error)) + goto out; + + if (!opt_gpg_verify_summary_set) + if (!ostree_repo_remote_get_gpg_verify_summary (self, pull_data->remote_name, + &pull_data->gpg_verify_summary, error)) + goto out; + + /* NOTE: If changing this, see the matching implementation in + * ostree-sysroot-upgrader.c + */ + if (!ostree_repo_get_remote_option (self, pull_data->remote_name, + "unconfigured-state", NULL, + &unconfigured_state, + error)) + goto out; + + if (unconfigured_state) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "remote unconfigured-state: %s", unconfigured_state); + goto out; + } + } + + if (pull_data->remote_name && !(disable_sign_verify && disable_sign_verify_summary)) + { + if (!_signapi_init_for_remote (pull_data->repo, pull_data->remote_name, + &pull_data->signapi_commit_verifiers, + &pull_data->signapi_summary_verifiers, + error)) + return FALSE; + } + + pull_data->phase = OSTREE_PULL_PHASE_FETCHING_REFS; + + if (!reinitialize_fetcher (pull_data, remote_name_or_baseurl, error)) + goto out; + + pull_data->tmpdir_dfd = pull_data->repo->tmp_dir_fd; + requested_refs_to_fetch = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + (GDestroyNotify) ostree_collection_ref_free, + g_free); + commits_to_fetch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + if (!ostree_repo_get_remote_option (self, + remote_name_or_baseurl, "metalink", + NULL, &metalink_url_str, error)) + goto out; + + if (!metalink_url_str) + { + g_autofree char *baseurl = NULL; + + if (url_override != NULL) + baseurl = g_strdup (url_override); + else if (!ostree_repo_remote_get_url (self, remote_name_or_baseurl, &baseurl, error)) + goto out; + + if (g_str_has_prefix (baseurl, "mirrorlist=")) + { + if (!fetch_mirrorlist (pull_data->fetcher, + baseurl + strlen ("mirrorlist="), + pull_data->n_network_retries, + &pull_data->meta_mirrorlist, + cancellable, error)) + goto out; + } + else + { + g_autoptr(OstreeFetcherURI) baseuri = _ostree_fetcher_uri_parse (baseurl, error); + + if (!baseuri) + goto out; + + pull_data->meta_mirrorlist = + g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free); + g_ptr_array_add (pull_data->meta_mirrorlist, g_steal_pointer (&baseuri)); + } + } + else + { + g_autoptr(GBytes) summary_bytes = NULL; + g_autoptr(OstreeFetcherURI) metalink_uri = _ostree_fetcher_uri_parse (metalink_url_str, error); + g_autoptr(OstreeFetcherURI) target_uri = NULL; + + if (!metalink_uri) + goto out; + + metalink = _ostree_metalink_new (pull_data->fetcher, "summary", + OSTREE_MAX_METADATA_SIZE, metalink_uri, + pull_data->n_network_retries); + + if (! _ostree_metalink_request_sync (metalink, + &target_uri, + &summary_bytes, + cancellable, + error)) + goto out; + + /* XXX: would be interesting to implement metalink as another source of + * mirrors here since we use it as such anyway (rather than the "usual" + * use case of metalink, which is only for a single target filename) */ + { + g_autofree char *path = _ostree_fetcher_uri_get_path (target_uri); + g_autofree char *basepath = g_path_get_dirname (path); + g_autoptr(OstreeFetcherURI) new_target_uri = _ostree_fetcher_uri_new_path (target_uri, basepath); + pull_data->meta_mirrorlist = + g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free); + g_ptr_array_add (pull_data->meta_mirrorlist, g_steal_pointer (&new_target_uri)); + } + + pull_data->summary = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE); + } + + { + g_autofree char *contenturl = NULL; + + if (metalink_url_str == NULL && url_override != NULL) + contenturl = g_strdup (url_override); + else if (!ostree_repo_get_remote_option (self, remote_name_or_baseurl, + "contenturl", NULL, + &contenturl, error)) + goto out; + + if (contenturl == NULL) + { + pull_data->content_mirrorlist = + g_ptr_array_ref (pull_data->meta_mirrorlist); + } + else + { + if (g_str_has_prefix (contenturl, "mirrorlist=")) + { + if (!fetch_mirrorlist (pull_data->fetcher, + contenturl + strlen ("mirrorlist="), + pull_data->n_network_retries, + &pull_data->content_mirrorlist, + cancellable, error)) + goto out; + } + else + { + g_autoptr(OstreeFetcherURI) contenturi = _ostree_fetcher_uri_parse (contenturl, error); + + if (!contenturi) + goto out; + + pull_data->content_mirrorlist = + g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free); + g_ptr_array_add (pull_data->content_mirrorlist, + g_steal_pointer (&contenturi)); + } + } + } + + /* FIXME: Do we want an analogue of this which supports collection IDs? */ + if (!ostree_repo_get_remote_list_option (self, + remote_name_or_baseurl, "branches", + &configured_branches, error)) + goto out; + + /* TODO reindent later */ + { OstreeFetcherURI *first_uri = pull_data->meta_mirrorlist->pdata[0]; + g_autofree char *first_scheme = _ostree_fetcher_uri_get_scheme (first_uri); + + /* NB: we don't support local mirrors in mirrorlists, so if this passes, it + * means that we're not using mirrorlists (see also fetch_mirrorlist()) + * Also, we explicitly disable the "local repo" path if static deltas + * were explicitly requested to be required; this is going to happen + * most often for testing deltas without setting up a HTTP server. + */ + if (g_str_equal (first_scheme, "file") && !pull_data->require_static_deltas) + { + g_autofree char *path = _ostree_fetcher_uri_get_path (first_uri); + g_autoptr(GFile) remote_repo_path = g_file_new_for_path (path); + pull_data->remote_repo_local = ostree_repo_new (remote_repo_path); + if (!ostree_repo_open (pull_data->remote_repo_local, cancellable, error)) + goto out; + } + else + { + if (!load_remote_repo_config (pull_data, &remote_config, cancellable, error)) + goto out; + + if (!ot_keyfile_get_value_with_default (remote_config, "core", "mode", "bare", + &remote_mode_str, error)) + goto out; + + if (!ostree_repo_mode_from_string (remote_mode_str, &pull_data->remote_mode, error)) + goto out; + + if (!ot_keyfile_get_boolean_with_default (remote_config, "core", "tombstone-commits", FALSE, + &pull_data->has_tombstone_commits, error)) + goto out; + + if (pull_data->remote_mode != OSTREE_REPO_MODE_ARCHIVE) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Can't pull from archives with mode \"%s\"", + remote_mode_str); + goto out; + } + } + } + + /* Change some option defaults if we're actually pulling from a local + * (filesystem accessible) repo. + */ + if (pull_data->remote_repo_local) + { + /* For local pulls, default to disabling static deltas so that the + * exact object files are copied. + */ + if (!pull_data->require_static_deltas) + pull_data->disable_static_deltas = TRUE; + + /* Note the inversion here; PULL_FLAGS_UNTRUSTED is converted to + * IMPORT_FLAGS_TRUSTED only if it's unset (and just for local repos). + */ + if ((flags & OSTREE_REPO_PULL_FLAGS_UNTRUSTED) == 0) + pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_TRUSTED; + + /* Shouldn't be referenced in this path, but just in case. See below + * for more information. + */ + pull_data->trusted_http_direct = FALSE; + } + else + { + /* For non-local repos, we require the TRUSTED_HTTP pull flag to map to + * the TRUSTED object import flag. In practice we don't do object imports + * for HTTP, but it's easiest to use one set of flags between HTTP and + * local imports. + */ + if (flags & OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP) + pull_data->importflags |= _OSTREE_REPO_IMPORT_FLAGS_TRUSTED; + + const gboolean verifying_bareuseronly = + (pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_VERIFY_BAREUSERONLY) > 0; + /* If we're mirroring and writing into an archive repo, and both checksum and + * bareuseronly are turned off, we can directly copy the content rather than + * paying the cost of exploding it, checksumming, and re-gzip. + */ + const gboolean mirroring_into_archive = + pull_data->is_mirror && pull_data->repo->mode == OSTREE_REPO_MODE_ARCHIVE; + const gboolean import_trusted = !verifying_bareuseronly && + (pull_data->importflags & _OSTREE_REPO_IMPORT_FLAGS_TRUSTED) > 0; + pull_data->trusted_http_direct = mirroring_into_archive && import_trusted; + } + + /* We can't use static deltas if pulling into an archive repo. */ + if (self->mode == OSTREE_REPO_MODE_ARCHIVE) + { + if (pull_data->require_static_deltas) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Can't use static deltas in an archive repo"); + goto out; + } + pull_data->disable_static_deltas = TRUE; + } + + /* It's not efficient to use static deltas if all we want is the commit + * metadata. */ + if (pull_data->is_commit_only) + pull_data->disable_static_deltas = TRUE; + + pull_data->static_delta_superblocks = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); + + { + g_autoptr(GBytes) bytes_sig = NULL; + gsize i, n; + g_autoptr(GVariant) refs = NULL; + g_autoptr(GVariant) deltas = NULL; + g_autoptr(GVariant) additional_metadata = NULL; + gboolean summary_from_cache = FALSE; + + if (!pull_data->summary_data_sig) + { + if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher, + pull_data->meta_mirrorlist, + "summary.sig", OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT, + pull_data->n_network_retries, + &bytes_sig, + OSTREE_MAX_METADATA_SIZE, + cancellable, error)) + goto out; + } + + if (bytes_sig && + !pull_data->remote_repo_local && + !_ostree_repo_load_cache_summary_if_same_sig (self, + remote_name_or_baseurl, + bytes_sig, + &bytes_summary, + cancellable, + error)) + goto out; + + if (bytes_summary) + { + g_debug ("Loaded %s summary from cache", remote_name_or_baseurl); + summary_from_cache = TRUE; + } + + if (!pull_data->summary && !bytes_summary) + { + if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher, + pull_data->meta_mirrorlist, + "summary", OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT, + pull_data->n_network_retries, + &bytes_summary, + OSTREE_MAX_METADATA_SIZE, + cancellable, error)) + goto out; + } + +#ifndef OSTREE_DISABLE_GPGME + if (!bytes_summary && pull_data->gpg_verify_summary) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "GPG verification enabled, but no summary found (use gpg-verify-summary=false in remote config to disable)"); + goto out; + } +#endif /* OSTREE_DISABLE_GPGME */ + + if (!bytes_summary && pull_data->require_static_deltas) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Fetch configured to require static deltas, but no summary found"); + goto out; + } + +#ifndef OSTREE_DISABLE_GPGME + if (!bytes_sig && pull_data->gpg_verify_summary) + { + g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, + "GPG verification enabled, but no summary.sig found (use gpg-verify-summary=false in remote config to disable)"); + goto out; + } + + if (pull_data->gpg_verify_summary && bytes_summary && bytes_sig) + { + g_autoptr(OstreeGpgVerifyResult) result = NULL; + g_autoptr(GError) temp_error = NULL; + + result = ostree_repo_verify_summary (self, pull_data->remote_name, + bytes_summary, bytes_sig, + cancellable, &temp_error); + if (!ostree_gpg_verify_result_require_valid_signature (result, &temp_error)) + { + if (summary_from_cache) + { + /* The cached summary doesn't match, fetch a new one and verify again */ + if ((self->test_error_flags & OSTREE_REPO_TEST_ERROR_INVALID_CACHE) > 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Remote %s cached summary invalid and " + "OSTREE_REPO_TEST_ERROR_INVALID_CACHE specified", + pull_data->remote_name); + goto out; + } + else + g_debug ("Remote %s cached summary invalid, pulling new version", + pull_data->remote_name); + + summary_from_cache = FALSE; + g_clear_pointer (&bytes_summary, (GDestroyNotify)g_bytes_unref); + if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher, + pull_data->meta_mirrorlist, + "summary", + OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT, + pull_data->n_network_retries, + &bytes_summary, + OSTREE_MAX_METADATA_SIZE, + cancellable, error)) + goto out; + + g_autoptr(OstreeGpgVerifyResult) retry = + ostree_repo_verify_summary (self, pull_data->remote_name, + bytes_summary, bytes_sig, + cancellable, error); + if (!ostree_gpg_verify_result_require_valid_signature (retry, error)) + goto out; + } + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + goto out; + } + } + } +#endif /* OSTREE_DISABLE_GPGME */ + + if (pull_data->signapi_summary_verifiers) + { + if (!bytes_sig && pull_data->signapi_summary_verifiers) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Signatures verification enabled, but no summary.sig found (use sign-verify-summary=false in remote config to disable)"); + goto out; + } + if (bytes_summary && bytes_sig) + { + g_autoptr(GVariant) signatures = NULL; + g_autoptr(GError) temp_error = NULL; + + signatures = g_variant_new_from_bytes (OSTREE_SUMMARY_SIG_GVARIANT_FORMAT, + bytes_sig, FALSE); + + + g_assert (pull_data->signapi_summary_verifiers); + if (!_sign_verify_for_remote (pull_data->signapi_summary_verifiers, bytes_summary, signatures, NULL, &temp_error)) + { + if (summary_from_cache) + { + /* The cached summary doesn't match, fetch a new one and verify again */ + if ((self->test_error_flags & OSTREE_REPO_TEST_ERROR_INVALID_CACHE) > 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Remote %s cached summary invalid and " + "OSTREE_REPO_TEST_ERROR_INVALID_CACHE specified", + pull_data->remote_name); + goto out; + } + else + g_debug ("Remote %s cached summary invalid, pulling new version", + pull_data->remote_name); + + summary_from_cache = FALSE; + g_clear_pointer (&bytes_summary, (GDestroyNotify)g_bytes_unref); + if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher, + pull_data->meta_mirrorlist, + "summary", + OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT, + pull_data->n_network_retries, + &bytes_summary, + OSTREE_MAX_METADATA_SIZE, + cancellable, error)) + goto out; + + if (!_sign_verify_for_remote (pull_data->signapi_summary_verifiers, bytes_summary, signatures, NULL, error)) + goto out; + } + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + goto out; + } + } + } + } + + if (bytes_summary) + { + pull_data->summary_data = g_bytes_ref (bytes_summary); + pull_data->summary = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, bytes_summary, FALSE); + + if (!g_variant_is_normal_form (pull_data->summary)) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Not normal form"); + goto out; + } + if (!g_variant_is_of_type (pull_data->summary, OSTREE_SUMMARY_GVARIANT_FORMAT)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Doesn't match variant type '%s'", + (char *)OSTREE_SUMMARY_GVARIANT_FORMAT); + goto out; + } + + if (bytes_sig) + pull_data->summary_data_sig = g_bytes_ref (bytes_sig); + } + + if (!summary_from_cache && bytes_summary && bytes_sig) + { + if (!pull_data->remote_repo_local && + !_ostree_repo_cache_summary (self, + remote_name_or_baseurl, + bytes_summary, + bytes_sig, + cancellable, + error)) + goto out; + } + + if (pull_data->summary) + { + additional_metadata = g_variant_get_child_value (pull_data->summary, 1); + + if (!g_variant_lookup (additional_metadata, OSTREE_SUMMARY_COLLECTION_ID, "&s", &main_collection_id)) + main_collection_id = NULL; + else if (!ostree_validate_collection_id (main_collection_id, error)) + goto out; + + refs = g_variant_get_child_value (pull_data->summary, 0); + for (i = 0, n = g_variant_n_children (refs); i < n; i++) + { + const char *refname; + g_autoptr(GVariant) ref = g_variant_get_child_value (refs, i); + + g_variant_get_child (ref, 0, "&s", &refname); + + if (!ostree_validate_rev (refname, error)) + goto out; + + if (pull_data->is_mirror && !refs_to_fetch && !opt_collection_refs_set) + { + g_hash_table_insert (requested_refs_to_fetch, + ostree_collection_ref_new (main_collection_id, refname), NULL); + } + } + + g_autoptr(GVariant) collection_map = NULL; + collection_map = g_variant_lookup_value (additional_metadata, OSTREE_SUMMARY_COLLECTION_MAP, G_VARIANT_TYPE ("a{sa(s(taya{sv}))}")); + if (collection_map != NULL) + { + GVariantIter collection_map_iter; + const char *collection_id; + g_autoptr(GVariant) collection_refs = NULL; + + g_variant_iter_init (&collection_map_iter, collection_map); + + while (g_variant_iter_loop (&collection_map_iter, "{&s@a(s(taya{sv}))}", &collection_id, &collection_refs)) + { + if (!ostree_validate_collection_id (collection_id, error)) + goto out; + + for (i = 0, n = g_variant_n_children (collection_refs); i < n; i++) + { + const char *refname; + g_autoptr(GVariant) ref = g_variant_get_child_value (collection_refs, i); + + g_variant_get_child (ref, 0, "&s", &refname); + + if (!ostree_validate_rev (refname, error)) + goto out; + + if (pull_data->is_mirror && !refs_to_fetch && !opt_collection_refs_set) + { + g_hash_table_insert (requested_refs_to_fetch, + ostree_collection_ref_new (collection_id, refname), NULL); + } + } + } + } + + deltas = g_variant_lookup_value (additional_metadata, OSTREE_SUMMARY_STATIC_DELTAS, G_VARIANT_TYPE ("a{sv}")); + n = deltas ? g_variant_n_children (deltas) : 0; + for (i = 0; i < n; i++) + { + const char *delta; + g_autoptr(GVariant) csum_v = NULL; + g_autoptr(GVariant) ref = g_variant_get_child_value (deltas, i); + + g_variant_get_child (ref, 0, "&s", &delta); + g_variant_get_child (ref, 1, "v", &csum_v); + + if (!validate_variant_is_csum (csum_v, error)) + goto out; + + guchar *csum_data = g_malloc (OSTREE_SHA256_DIGEST_LEN); + memcpy (csum_data, ostree_checksum_bytes_peek (csum_v), 32); + g_hash_table_insert (pull_data->summary_deltas_checksums, + g_strdup (delta), + csum_data); + } + } + } + + if (pull_data->is_mirror && !refs_to_fetch && !opt_collection_refs_set && !configured_branches) + { + if (!bytes_summary) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Fetching all refs was requested in mirror mode, but remote repository does not have a summary"); + goto out; + } + + } + else if (opt_collection_refs_set) + { + const gchar *collection_id, *ref_name, *checksum; + + while (g_variant_iter_loop (collection_refs_iter, "(&s&s&s)", &collection_id, &ref_name, &checksum)) + { + if (!ostree_validate_rev (ref_name, error)) + goto out; + g_hash_table_insert (requested_refs_to_fetch, + ostree_collection_ref_new (collection_id, ref_name), + (*checksum != '\0') ? g_strdup (checksum) : NULL); + } + } + else if (refs_to_fetch != NULL) + { + char **strviter = refs_to_fetch; + char **commitid_strviter = override_commit_ids ?: NULL; + + while (*strviter) + { + const char *branch = *strviter; + + if (ostree_validate_checksum_string (branch, NULL)) + { + char *key = g_strdup (branch); + g_hash_table_add (commits_to_fetch, key); + } + else + { + if (!ostree_validate_rev (branch, error)) + goto out; + char *commitid = commitid_strviter ? g_strdup (*commitid_strviter) : NULL; + g_hash_table_insert (requested_refs_to_fetch, + ostree_collection_ref_new (NULL, branch), commitid); + } + + strviter++; + if (commitid_strviter) + commitid_strviter++; + } + } + else + { + char **branches_iter; + + branches_iter = configured_branches; + + if (!(branches_iter && *branches_iter)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No configured branches for remote %s", remote_name_or_baseurl); + goto out; + } + for (;branches_iter && *branches_iter; branches_iter++) + { + const char *branch = *branches_iter; + + g_hash_table_insert (requested_refs_to_fetch, + ostree_collection_ref_new (NULL, branch), NULL); + } + } + + /* Resolve the checksum for each ref. This has to be done into a new hash table, + * since we can’t modify the keys of @requested_refs_to_fetch while iterating + * over it, and we need to ensure the collection IDs are resolved too. */ + updated_requested_refs_to_fetch = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + (GDestroyNotify) ostree_collection_ref_free, + g_free); + GLNX_HASH_TABLE_FOREACH_KV (requested_refs_to_fetch, const OstreeCollectionRef*, ref, + const char*, override_commitid) + { + g_autofree char *checksum = NULL; + g_autoptr(OstreeCollectionRef) ref_with_collection = NULL; + + /* Support specifying "" for an override commitid */ + if (override_commitid && *override_commitid) + { + ref_with_collection = ostree_collection_ref_dup (ref); + checksum = g_strdup (override_commitid); + } + else + { + if (pull_data->summary) + { + gsize commit_size = 0; + guint64 *malloced_size; + g_autofree gchar *collection_id = NULL; + + if (!lookup_commit_checksum_and_collection_from_summary (pull_data, ref, &checksum, &commit_size, &collection_id, error)) + goto out; + + ref_with_collection = ostree_collection_ref_new (collection_id, ref->ref_name); + + malloced_size = g_new0 (guint64, 1); + *malloced_size = commit_size; + g_hash_table_insert (pull_data->expected_commit_sizes, g_strdup (checksum), malloced_size); + } + else + { + if (!fetch_ref_contents (pull_data, main_collection_id, ref, &checksum, cancellable, error)) + goto out; + + ref_with_collection = ostree_collection_ref_dup (ref); + } + } + + /* If we have timestamp checking enabled, find the current value of + * the ref, and store its timestamp in the hash map, to check later. + */ + if (pull_data->timestamp_check) + { + g_autofree char *from_rev = NULL; + if (!ostree_repo_resolve_rev (pull_data->repo, ref_with_collection->ref_name, TRUE, + &from_rev, error)) + goto out; + /* Explicitly store NULL if there's no previous revision. We do + * this so we can assert() if we somehow didn't find a ref in the + * hash at all. Note we don't copy the collection-ref, so the + * lifetime of this hash must be equal to `requested_refs_to_fetch`. + */ + g_hash_table_insert (pull_data->ref_original_commits, ref_with_collection, + g_steal_pointer (&from_rev)); + } + + g_hash_table_replace (updated_requested_refs_to_fetch, + g_steal_pointer (&ref_with_collection), + g_steal_pointer (&checksum)); + } + + /* Resolve refs to a checksum if necessary */ + if (pull_data->timestamp_check_from_rev && + !ostree_validate_checksum_string (pull_data->timestamp_check_from_rev, NULL)) + { + g_autofree char *from_rev = NULL; + if (!ostree_repo_resolve_rev (pull_data->repo, pull_data->timestamp_check_from_rev, FALSE, + &from_rev, error)) + goto out; + g_free (pull_data->timestamp_check_from_rev); + pull_data->timestamp_check_from_rev = g_steal_pointer (&from_rev); + } + + g_hash_table_unref (requested_refs_to_fetch); + requested_refs_to_fetch = g_steal_pointer (&updated_requested_refs_to_fetch); + if (g_hash_table_size (requested_refs_to_fetch) == 1) + { + GLNX_HASH_TABLE_FOREACH (requested_refs_to_fetch, + const OstreeCollectionRef *, ref) + { + the_ref_to_fetch = ref->ref_name; + break; + } + } + + if (opt_ref_keyring_map_set) + { + const gchar *collection_id, *ref_name, *keyring_remote_name; + + while (g_variant_iter_loop (ref_keyring_map_iter, "(&s&s&s)", &collection_id, &ref_name, &keyring_remote_name)) + { + g_autoptr(OstreeCollectionRef) c_r = NULL; + + if (!ostree_validate_collection_id (collection_id, error)) + goto out; + if (!ostree_validate_rev (ref_name, error)) + goto out; + if (!ostree_validate_remote_name (keyring_remote_name, error)) + goto out; + + c_r = ostree_collection_ref_new (collection_id, ref_name); + if (!g_hash_table_contains (requested_refs_to_fetch, c_r)) + continue; + g_hash_table_insert (pull_data->ref_keyring_map, + g_steal_pointer (&c_r), + g_strdup (keyring_remote_name)); + } + } + + /* Create the state directory here - it's new with the commitpartial code, + * and may not exist in older repositories. + */ + if (mkdirat (pull_data->repo->repo_dir_fd, "state", 0777) != 0) + { + if (G_UNLIKELY (errno != EEXIST)) + { + glnx_set_error_from_errno (error); + goto out; + } + } + + pull_data->phase = OSTREE_PULL_PHASE_FETCHING_OBJECTS; + + /* Now discard the previous fetcher, as it was bound to a temporary main context + * for synchronous requests. + */ + if (!reinitialize_fetcher (pull_data, remote_name_or_baseurl, error)) + goto out; + + pull_data->legacy_transaction_resuming = FALSE; + if (!inherit_transaction && + !ostree_repo_prepare_transaction (pull_data->repo, &pull_data->legacy_transaction_resuming, + cancellable, error)) + goto out; + + if (pull_data->legacy_transaction_resuming) + g_debug ("resuming legacy transaction"); + + /* Initiate requests for explicit commit revisions */ + GLNX_HASH_TABLE_FOREACH_V (commits_to_fetch, const char*, commit) + { + if (!initiate_request (pull_data, NULL, commit, error)) + goto out; + } + + /* Initiate requests for refs */ + GLNX_HASH_TABLE_FOREACH_KV (requested_refs_to_fetch, const OstreeCollectionRef*, ref, + const char*, to_revision) + { + if (!initiate_request (pull_data, ref, to_revision, error)) + goto out; + } + + if (pull_data->progress) + { + /* Setup a custom frequency if set */ + if (update_frequency > 0) + update_timeout = g_timeout_source_new (pull_data->dry_run ? 0 : update_frequency); + else + update_timeout = g_timeout_source_new_seconds (pull_data->dry_run ? 0 : 1); + + g_source_set_priority (update_timeout, G_PRIORITY_HIGH); + g_source_set_callback (update_timeout, update_progress, pull_data, NULL); + g_source_attach (update_timeout, pull_data->main_context); + } + + /* Now await work completion */ + while (!pull_termination_condition (pull_data)) + g_main_context_iteration (pull_data->main_context, TRUE); + + if (pull_data->caught_error) + goto out; + + if (pull_data->dry_run) + { + ret = TRUE; + goto out; + } + + g_assert_cmpint (pull_data->n_outstanding_metadata_fetches, ==, 0); + g_assert_cmpint (pull_data->n_outstanding_metadata_write_requests, ==, 0); + g_assert_cmpint (pull_data->n_outstanding_content_fetches, ==, 0); + g_assert_cmpint (pull_data->n_outstanding_content_write_requests, ==, 0); + + GLNX_HASH_TABLE_FOREACH_KV (requested_refs_to_fetch, const OstreeCollectionRef*, ref, + const char*, checksum) + { + g_autofree char *remote_ref = NULL; + g_autofree char *original_rev = NULL; + + if (pull_data->remote_name) + remote_ref = g_strdup_printf ("%s:%s", pull_data->remote_name, ref->ref_name); + else + remote_ref = g_strdup (ref->ref_name); + + if (!ostree_repo_resolve_rev (pull_data->repo, remote_ref, TRUE, &original_rev, error)) + goto out; + + if (original_rev && strcmp (checksum, original_rev) == 0) + { + } + else + { + if (pull_data->is_mirror) + ostree_repo_transaction_set_collection_ref (pull_data->repo, + ref, checksum); + else + ostree_repo_transaction_set_ref (pull_data->repo, + pull_data->remote_refspec_name ?: pull_data->remote_name, + ref->ref_name, checksum); + } + } + + if (pull_data->is_mirror && pull_data->summary_data && + !refs_to_fetch && !opt_collection_refs_set && !configured_branches) + { + GLnxFileReplaceFlags replaceflag = + pull_data->repo->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : 0; + gsize len; + const guint8 *buf = g_bytes_get_data (pull_data->summary_data, &len); + + if (!glnx_file_replace_contents_at (pull_data->repo->repo_dir_fd, "summary", + buf, len, replaceflag, + cancellable, error)) + goto out; + + if (pull_data->summary_data_sig) + { + buf = g_bytes_get_data (pull_data->summary_data_sig, &len); + if (!glnx_file_replace_contents_at (pull_data->repo->repo_dir_fd, "summary.sig", + buf, len, replaceflag, + cancellable, error)) + goto out; + } + } + + if (!inherit_transaction && + !ostree_repo_commit_transaction (pull_data->repo, &tstats, cancellable, error)) + goto out; + + end_time = g_get_monotonic_time (); + + bytes_transferred = _ostree_fetcher_bytes_transferred (pull_data->fetcher); + if (pull_data->progress) + { + g_autoptr(GString) buf = g_string_new (""); + + /* Ensure the rest of the progress keys are set appropriately. */ + update_progress (pull_data); + + /* See if we did a local-only import */ + if (pull_data->remote_repo_local) + g_string_append_printf (buf, "%u metadata, %u content objects imported", + pull_data->n_imported_metadata, pull_data->n_imported_content); + else if (pull_data->n_fetched_deltaparts > 0) + g_string_append_printf (buf, "%u delta parts, %u loose fetched", + pull_data->n_fetched_deltaparts, + pull_data->n_fetched_metadata + pull_data->n_fetched_content); + else + g_string_append_printf (buf, "%u metadata, %u content objects fetched", + pull_data->n_fetched_metadata, pull_data->n_fetched_content); + if (!pull_data->remote_repo_local && + (pull_data->n_imported_metadata || pull_data->n_imported_content)) + g_string_append_printf (buf, " (%u meta, %u content local)", + pull_data->n_imported_metadata, + pull_data->n_imported_content); + + if (bytes_transferred > 0) + { + guint shift; + if (bytes_transferred < 1024) + shift = 1; + else + shift = 1024; + g_string_append_printf (buf, "; %" G_GUINT64_FORMAT " %s transferred in %u seconds", + (guint64)(bytes_transferred / shift), + shift == 1 ? "B" : "KiB", + (guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC)); + } + if (!inherit_transaction) + { + g_autofree char *bytes_written = g_format_size (tstats.content_bytes_written); + g_string_append_printf (buf, "; %s content written", bytes_written); + } + + ostree_async_progress_set_status (pull_data->progress, buf->str); + } + +#ifdef HAVE_LIBSYSTEMD + if (bytes_transferred > 0 && pull_data->remote_name) + { + g_autoptr(GString) msg = g_string_new (""); + if (the_ref_to_fetch) + g_string_append_printf (msg, "libostree pull from '%s' for %s complete", + pull_data->remote_name, the_ref_to_fetch); + else + g_string_append_printf (msg, "libostree pull from '%s' for %u refs complete", + pull_data->remote_name, g_hash_table_size (requested_refs_to_fetch)); + + const char *gpg_verify_state; +#ifndef OSTREE_DISABLE_GPGME + if (pull_data->gpg_verify_summary) + { + if (pull_data->gpg_verify) + gpg_verify_state = "summary+commit"; + else + gpg_verify_state = "summary-only"; + } + else + gpg_verify_state = (pull_data->gpg_verify ? "commit" : "disabled"); + +#else + gpg_verify_state = "disabled"; +#endif /* OSTREE_DISABLE_GPGME */ + g_string_append_printf (msg, "\nsecurity: GPG: %s ", gpg_verify_state); + + const char *sign_verify_state; + sign_verify_state = (pull_data->signapi_commit_verifiers ? "commit" : "disabled"); + g_string_append_printf (msg, "\nsecurity: SIGN: %s ", sign_verify_state); + + OstreeFetcherURI *first_uri = pull_data->meta_mirrorlist->pdata[0]; + g_autofree char *first_scheme = _ostree_fetcher_uri_get_scheme (first_uri); + if (g_str_has_prefix (first_scheme, "http")) + { + g_string_append (msg, "http: "); + switch (pull_data->fetcher_security_state) + { + case OSTREE_FETCHER_SECURITY_STATE_CA_PINNED: + g_string_append (msg, "CA-pinned"); + break; + case OSTREE_FETCHER_SECURITY_STATE_TLS: + g_string_append (msg, "TLS"); + break; + case OSTREE_FETCHER_SECURITY_STATE_INSECURE: + g_string_append (msg, "insecure"); + break; + } + } + g_string_append (msg, "\n"); + + if (pull_data->n_fetched_deltaparts > 0) + g_string_append_printf (msg, "delta: parts: %u loose: %u", + pull_data->n_fetched_deltaparts, + pull_data->n_fetched_metadata + pull_data->n_fetched_content); + else + g_string_append_printf (msg, "non-delta: meta: %u content: %u", + pull_data->n_fetched_metadata, pull_data->n_fetched_content); + const guint n_seconds = (guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC); + g_autofree char *formatted_xferred = g_format_size (bytes_transferred); + g_string_append_printf (msg, "\ntransfer: secs: %u size: %s", n_seconds, formatted_xferred); + if (pull_data->signapi_commit_verifiers) + { + g_assert_cmpuint (g_hash_table_size (pull_data->signapi_verified_commits), >, 0); + } + + ot_journal_send ("MESSAGE=%s", msg->str, + "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_MESSAGE_FETCH_COMPLETE_ID), + "OSTREE_REMOTE=%s", pull_data->remote_name, + "OSTREE_SIGN=%s", sign_verify_state, + "OSTREE_GPG=%s", gpg_verify_state, + "OSTREE_SECONDS=%u", n_seconds, + "OSTREE_XFER_SIZE=%s", formatted_xferred, + NULL); + } +#endif + + /* iterate over commits fetched and delete any commitpartial files */ + if (pull_data->dirs == NULL && !pull_data->is_commit_only) + { + GLNX_HASH_TABLE_FOREACH_V (requested_refs_to_fetch, const char*, checksum) + { + if (!ostree_repo_mark_commit_partial (pull_data->repo, checksum, FALSE, error)) + goto out; + } + + GLNX_HASH_TABLE_FOREACH_V (commits_to_fetch, const char*, commit) + { + if (!ostree_repo_mark_commit_partial (pull_data->repo, commit, FALSE, error)) + goto out; + } + + /* and finally any parent commits we might also have pulled because of depth>0 */ + GLNX_HASH_TABLE_FOREACH (pull_data->commit_to_depth, const char*, commit) + { + if (!ostree_repo_mark_commit_partial (pull_data->repo, commit, FALSE, error)) + goto out; + } + } + + ret = TRUE; + out: + /* This is pretty ugly - we have two error locations, because we + * have a mix of synchronous and async code. Mixing them gets messy + * as we need to avoid overwriting errors. + */ + if (pull_data->cached_async_error && error && !*error) + g_propagate_error (error, pull_data->cached_async_error); + else + g_clear_error (&pull_data->cached_async_error); + + if (!inherit_transaction) + ostree_repo_abort_transaction (pull_data->repo, cancellable, NULL); + g_main_context_unref (pull_data->main_context); + if (update_timeout) + g_source_destroy (update_timeout); + g_strfreev (configured_branches); + g_clear_object (&pull_data->fetcher); + g_clear_pointer (&pull_data->extra_headers, (GDestroyNotify)g_variant_unref); + g_clear_object (&pull_data->cancellable); + g_clear_pointer (&pull_data->localcache_repos, (GDestroyNotify)g_ptr_array_unref); + g_clear_object (&pull_data->remote_repo_local); + g_free (pull_data->remote_refspec_name); + g_free (pull_data->remote_name); + g_free (pull_data->append_user_agent); + g_clear_pointer (&pull_data->signapi_commit_verifiers, (GDestroyNotify) g_ptr_array_unref); + g_clear_pointer (&pull_data->signapi_summary_verifiers, (GDestroyNotify) g_ptr_array_unref); + g_clear_pointer (&pull_data->meta_mirrorlist, (GDestroyNotify) g_ptr_array_unref); + g_clear_pointer (&pull_data->content_mirrorlist, (GDestroyNotify) g_ptr_array_unref); + g_clear_pointer (&pull_data->summary_data, (GDestroyNotify) g_bytes_unref); + g_clear_pointer (&pull_data->summary_data_sig, (GDestroyNotify) g_bytes_unref); + g_clear_pointer (&pull_data->summary, (GDestroyNotify) g_variant_unref); + g_clear_pointer (&pull_data->static_delta_superblocks, (GDestroyNotify) g_ptr_array_unref); + g_clear_pointer (&pull_data->commit_to_depth, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->expected_commit_sizes, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->scanned_metadata, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->fetched_detached_metadata, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->summary_deltas_checksums, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->ref_original_commits, (GDestroyNotify) g_hash_table_unref); + g_free (pull_data->timestamp_check_from_rev); + g_clear_pointer (&pull_data->verified_commits, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->signapi_verified_commits, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->ref_keyring_map, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->requested_content, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->requested_fallback_content, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->requested_metadata, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->pending_fetch_content, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->pending_fetch_metadata, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->pending_fetch_delta_superblocks, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->pending_fetch_deltaparts, (GDestroyNotify) g_hash_table_unref); + g_queue_foreach (&pull_data->scan_object_queue, (GFunc) scan_object_queue_data_free, NULL); + g_queue_clear (&pull_data->scan_object_queue); + g_clear_pointer (&pull_data->idle_src, (GDestroyNotify) g_source_destroy); + g_clear_pointer (&pull_data->dirs, (GDestroyNotify) g_ptr_array_unref); + g_clear_pointer (&remote_config, (GDestroyNotify) g_key_file_unref); + return ret; +} + +/* Structure used in ostree_repo_find_remotes_async() which stores metadata + * about a given OSTree commit. This includes the metadata from the commit + * #GVariant, plus some working state which is used to work out which remotes + * have refs pointing to this commit. */ +typedef struct +{ + gchar *checksum; /* always set */ + guint64 commit_size; /* always set */ + guint64 timestamp; /* 0 for unknown */ + GVariant *additional_metadata; + GArray *refs; /* (element-type gsize), indexes to refs which point to this commit on at least one remote */ +} CommitMetadata; + +static void +commit_metadata_free (CommitMetadata *info) +{ + g_clear_pointer (&info->refs, g_array_unref); + g_free (info->checksum); + g_clear_pointer (&info->additional_metadata, g_variant_unref); + g_free (info); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (CommitMetadata, commit_metadata_free) + +static CommitMetadata * +commit_metadata_new (const gchar *checksum, + guint64 commit_size, + guint64 timestamp, + GVariant *additional_metadata) +{ + g_autoptr(CommitMetadata) info = NULL; + + info = g_new0 (CommitMetadata, 1); + info->checksum = g_strdup (checksum); + info->commit_size = commit_size; + info->timestamp = timestamp; + info->additional_metadata = (additional_metadata != NULL) ? g_variant_ref (additional_metadata) : NULL; + info->refs = g_array_new (FALSE, FALSE, sizeof (gsize)); + + return g_steal_pointer (&info); +} + +/* Structure used in ostree_repo_find_remotes_async() to store a grid (or table) + * of pointers, indexed by rows and columns. Basically an encapsulated 2D array. + * See the comments in ostree_repo_find_remotes_async() for its semantics + * there. */ +typedef struct +{ + gsize width; /* pointers */ + gsize height; /* pointers */ + gconstpointer pointers[]; /* n_pointers = width * height */ +} PointerTable; + +static void +pointer_table_free (PointerTable *table) +{ + g_free (table); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (PointerTable, pointer_table_free) + +/* Both dimensions are in numbers of pointers. */ +static PointerTable * +pointer_table_new (gsize width, + gsize height) +{ + g_autoptr(PointerTable) table = NULL; + + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + g_return_val_if_fail (width <= (G_MAXSIZE - sizeof (PointerTable)) / sizeof (gconstpointer) / height, NULL); + + table = g_malloc0 (sizeof (PointerTable) + sizeof (gconstpointer) * width * height); + table->width = width; + table->height = height; + + return g_steal_pointer (&table); +} + +static gconstpointer +pointer_table_get (const PointerTable *table, + gsize x, + gsize y) +{ + g_return_val_if_fail (table != NULL, FALSE); + g_return_val_if_fail (x < table->width, FALSE); + g_return_val_if_fail (y < table->height, FALSE); + + return table->pointers[table->width * y + x]; +} + +static void +pointer_table_set (PointerTable *table, + gsize x, + gsize y, + gconstpointer value) +{ + g_return_if_fail (table != NULL); + g_return_if_fail (x < table->width); + g_return_if_fail (y < table->height); + + table->pointers[table->width * y + x] = value; +} + +/* Validate the given struct contains a valid collection ID and ref name. */ +static gboolean +is_valid_collection_ref (const OstreeCollectionRef *ref) +{ + return (ref != NULL && + ostree_validate_rev (ref->ref_name, NULL) && + ostree_validate_collection_id (ref->collection_id, NULL)); +} + +/* Validate @refs is non-%NULL, non-empty, and contains only valid collection + * and ref names. */ +static gboolean +is_valid_collection_ref_array (const OstreeCollectionRef * const *refs) +{ + gsize i; + + if (refs == NULL || *refs == NULL) + return FALSE; + + for (i = 0; refs[i] != NULL; i++) + { + if (!is_valid_collection_ref (refs[i])) + return FALSE; + } + + return TRUE; +} + +/* Validate @finders is non-%NULL, non-empty, and contains only valid + * #OstreeRepoFinder instances. */ +static gboolean +is_valid_finder_array (OstreeRepoFinder **finders) +{ + gsize i; + + if (finders == NULL || *finders == NULL) + return FALSE; + + for (i = 0; finders[i] != NULL; i++) + { + if (!OSTREE_IS_REPO_FINDER (finders[i])) + return FALSE; + } + + return TRUE; +} + +/* Closure used to carry inputs from ostree_repo_find_remotes_async() to + * find_remotes_cb(). */ +typedef struct +{ + OstreeCollectionRef **refs; + GVariant *options; + OstreeAsyncProgress *progress; + OstreeRepoFinder *default_finder_avahi; + guint n_network_retries; +} FindRemotesData; + +static void +find_remotes_data_free (FindRemotesData *data) +{ + g_clear_object (&data->default_finder_avahi); + g_clear_object (&data->progress); + g_clear_pointer (&data->options, g_variant_unref); + ostree_collection_ref_freev (data->refs); + + g_free (data); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (FindRemotesData, find_remotes_data_free) + +static FindRemotesData * +find_remotes_data_new (const OstreeCollectionRef * const *refs, + GVariant *options, + OstreeAsyncProgress *progress, + OstreeRepoFinder *default_finder_avahi, + guint n_network_retries) +{ + g_autoptr(FindRemotesData) data = NULL; + + data = g_new0 (FindRemotesData, 1); + data->refs = ostree_collection_ref_dupv (refs); + data->options = (options != NULL) ? g_variant_ref (options) : NULL; + data->progress = (progress != NULL) ? g_object_ref (progress) : NULL; + data->default_finder_avahi = (default_finder_avahi != NULL) ? g_object_ref (default_finder_avahi) : NULL; + data->n_network_retries = n_network_retries; + + return g_steal_pointer (&data); +} + +static gchar * +uint64_secs_to_iso8601 (guint64 secs) +{ + g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (secs); + + if (dt != NULL) + return g_date_time_format (dt, "%FT%TZ"); + else + return g_strdup ("invalid"); +} + +static gint +sort_results_cb (gconstpointer a, + gconstpointer b) +{ + const OstreeRepoFinderResult **result_a = (const OstreeRepoFinderResult **) a; + const OstreeRepoFinderResult **result_b = (const OstreeRepoFinderResult **) b; + + return ostree_repo_finder_result_compare (*result_a, *result_b); +} + +static void +repo_finder_result_free0 (OstreeRepoFinderResult *result) +{ + if (result == NULL) + return; + + ostree_repo_finder_result_free (result); +} + +static void find_remotes_cb (GObject *obj, + GAsyncResult *result, + gpointer user_data); + +/** + * ostree_repo_find_remotes_async: + * @self: an #OstreeRepo + * @refs: (array zero-terminated=1): non-empty array of collection–ref pairs to find remotes for + * @options: (nullable): a GVariant `a{sv}` with an extensible set of flags + * @finders: (array zero-terminated=1) (transfer none): non-empty array of + * #OstreeRepoFinder instances to use, or %NULL to use the system defaults + * @progress: (nullable): an #OstreeAsyncProgress to update with the operation’s + * progress, or %NULL + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: asynchronous completion callback + * @user_data: data to pass to @callback + * + * Find reachable remote URIs which claim to provide any of the given named + * @refs. This will search for configured remotes (#OstreeRepoFinderConfig), + * mounted volumes (#OstreeRepoFinderMount) and (if enabled at compile time) + * local network peers (#OstreeRepoFinderAvahi). In order to use a custom + * configuration of #OstreeRepoFinder instances, call + * ostree_repo_finder_resolve_all_async() on them individually. + * + * Any remote which is found and which claims to support any of the given @refs + * will be returned in the results. It is possible that a remote claims to + * support a given ref, but turns out not to — it is not possible to verify this + * until ostree_repo_pull_from_remotes_async() is called. + * + * The returned results will be sorted with the most useful first — this is + * typically the remote which claims to provide the most of @refs, at the lowest + * latency. + * + * Each result contains a list of the subset of @refs it claims to provide. It + * is possible for a non-empty list of results to be returned, but for some of + * @refs to not be listed in any of the results. Callers must check for this. + * + * Pass the results to ostree_repo_pull_from_remotes_async() to pull the given @refs + * from those remotes. + * + * The following @options are currently defined: + * + * * `override-commit-ids` (`as`): Array of specific commit IDs to fetch. The nth + * commit ID applies to the nth ref, so this must be the same length as @refs, if + * provided. + * * `n-network-retries` (`u`): Number of times to retry each download on + * receiving a transient network error, such as a socket timeout; default is + * 5, 0 means return errors without retrying. Since: 2018.6 + * + * @finders must be a non-empty %NULL-terminated array of the #OstreeRepoFinder + * instances to use, or %NULL to use the system default set of finders, which + * will typically be all available finders using their default options (but + * this is not guaranteed). + * + * GPG verification of commits will be used unconditionally. + * + * This will use the thread-default #GMainContext, but will not iterate it. + * + * Since: 2018.6 + */ +void +ostree_repo_find_remotes_async (OstreeRepo *self, + const OstreeCollectionRef * const *refs, + GVariant *options, + OstreeRepoFinder **finders, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + g_autoptr(FindRemotesData) data = NULL; + OstreeRepoFinder *default_finders[4] = { NULL, }; + g_autoptr(OstreeRepoFinder) finder_config = NULL; + g_autoptr(OstreeRepoFinder) finder_mount = NULL; + g_autoptr(OstreeRepoFinder) finder_avahi = NULL; + g_autofree char **override_commit_ids = NULL; + guint n_network_retries = DEFAULT_N_NETWORK_RETRIES; + + g_return_if_fail (OSTREE_IS_REPO (self)); + g_return_if_fail (is_valid_collection_ref_array (refs)); + g_return_if_fail (options == NULL || + g_variant_is_of_type (options, G_VARIANT_TYPE_VARDICT)); + g_return_if_fail (finders == NULL || is_valid_finder_array (finders)); + g_return_if_fail (progress == NULL || OSTREE_IS_ASYNC_PROGRESS (progress)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + if (options) + { + (void) g_variant_lookup (options, "override-commit-ids", "^a&s", &override_commit_ids); + g_return_if_fail (override_commit_ids == NULL || g_strv_length ((gchar **) refs) == g_strv_length (override_commit_ids)); + + (void) g_variant_lookup (options, "n-network-retries", "u", &n_network_retries); + } + + /* Set up a task for the whole operation. */ + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, ostree_repo_find_remotes_async); + + /* Are we using #OstreeRepoFinders provided by the user, or the defaults? */ + if (finders == NULL) + { + guint finder_index = 0; +#ifdef HAVE_AVAHI + guint avahi_index; + GMainContext *context = g_main_context_get_thread_default (); + g_autoptr(GError) local_error = NULL; +#endif /* HAVE_AVAHI */ + + if (g_strv_contains ((const char * const *)self->repo_finders, "config")) + default_finders[finder_index++] = finder_config = OSTREE_REPO_FINDER (ostree_repo_finder_config_new ()); + + if (g_strv_contains ((const char * const *)self->repo_finders, "mount")) + default_finders[finder_index++] = finder_mount = OSTREE_REPO_FINDER (ostree_repo_finder_mount_new (NULL)); + +#ifdef HAVE_AVAHI + if (g_strv_contains ((const char * const *)self->repo_finders, "lan")) + { + avahi_index = finder_index; + default_finders[finder_index++] = finder_avahi = OSTREE_REPO_FINDER (ostree_repo_finder_avahi_new (context)); + } +#endif /* HAVE_AVAHI */ + + /* self->repo_finders is guaranteed to be non-empty */ + g_assert (default_finders != NULL); + finders = default_finders; + +#ifdef HAVE_AVAHI + if (finder_avahi != NULL) + { + ostree_repo_finder_avahi_start (OSTREE_REPO_FINDER_AVAHI (finder_avahi), + &local_error); + + if (local_error != NULL) + { + /* See ostree-repo-finder-avahi.c:ostree_repo_finder_avahi_start, we + * intentionally throw this so as to distinguish between the Avahi + * finder failing because the Avahi daemon wasn't running and + * the Avahi finder failing because of some actual error. + * + * We need to distinguish between g_debug and g_warning here because + * unit tests that use this code may set G_DEBUG=fatal-warnings which + * would cause client code to abort if a warning were emitted. + */ + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + g_debug ("Avahi finder failed under normal operation; removing it: %s", local_error->message); + else + g_warning ("Avahi finder failed abnormally; removing it: %s", local_error->message); + + default_finders[avahi_index] = NULL; + g_clear_object (&finder_avahi); + } + } +#endif /* HAVE_AVAHI */ + } + + /* We need to keep a pointer to the default Avahi finder so we can stop it + * again after the operation, which happens implicitly by dropping the final + * ref. */ + data = find_remotes_data_new (refs, options, progress, finder_avahi, n_network_retries); + g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) find_remotes_data_free); + + /* Asynchronously resolve all possible remotes for the given refs. */ + ostree_repo_finder_resolve_all_async (finders, refs, self, cancellable, + find_remotes_cb, g_steal_pointer (&task)); +} + +/* Find the first instance of (@collection_id, @ref_name) in @refs and return + * its index; or return %FALSE if nothing’s found. */ +static gboolean +collection_refv_contains (const OstreeCollectionRef * const *refs, + const gchar *collection_id, + const gchar *ref_name, + gsize *out_index) +{ + gsize i; + + for (i = 0; refs[i] != NULL; i++) + { + if (g_str_equal (refs[i]->collection_id, collection_id) && + g_str_equal (refs[i]->ref_name, ref_name)) + { + *out_index = i; + return TRUE; + } + } + + return FALSE; +} + +/* For each ref from @refs which is listed in @summary_refs, cache its metadata + * from the summary file entry into @commit_metadatas, and add the checksum it + * points to into @refs_and_remotes_table at (@ref_index, @result_index). + * @ref_index is the ref’s index in @refs. */ +static gboolean +find_remotes_process_refs (OstreeRepo *self, + const OstreeCollectionRef * const *refs, + OstreeRepoFinderResult *result, + gsize result_index, + const gchar *summary_collection_id, + GVariant *summary_refs, + GHashTable *commit_metadatas, + PointerTable *refs_and_remotes_table) +{ + gsize j, n; + + for (j = 0, n = g_variant_n_children (summary_refs); j < n; j++) + { + const guchar *csum_bytes; + g_autoptr(GVariant) ref_v = NULL, csum_v = NULL, commit_metadata_v = NULL, stored_commit_v = NULL; + guint64 commit_size, commit_timestamp; + gchar tmp_checksum[OSTREE_SHA256_STRING_LEN + 1]; + gsize ref_index; + g_autoptr(GDateTime) dt = NULL; + g_autoptr(GError) error = NULL; + const gchar *ref_name; + CommitMetadata *commit_metadata; + + /* Check the ref name. */ + ref_v = g_variant_get_child_value (summary_refs, j); + g_variant_get_child (ref_v, 0, "&s", &ref_name); + + if (!ostree_validate_rev (ref_name, &error)) + { + g_debug ("%s: Summary for result ‘%s’ contained invalid ref name ‘%s’: %s", + G_STRFUNC, result->remote->name, ref_name, error->message); + return FALSE; + } + + /* Check the commit checksum. */ + g_variant_get_child (ref_v, 1, "(t@ay@a{sv})", &commit_size, &csum_v, &commit_metadata_v); + + csum_bytes = ostree_checksum_bytes_peek_validate (csum_v, &error); + if (csum_bytes == NULL) + { + g_debug ("%s: Summary for result ‘%s’ contained invalid ref checksum: %s", + G_STRFUNC, result->remote->name, error->message); + return FALSE; + } + + ostree_checksum_inplace_from_bytes (csum_bytes, tmp_checksum); + + /* Is this a ref we care about? */ + if (!collection_refv_contains (refs, summary_collection_id, ref_name, &ref_index)) + continue; + + /* Load the commit from disk if possible, for verification. */ + if (!ostree_repo_load_commit (self, tmp_checksum, &stored_commit_v, NULL, NULL)) + stored_commit_v = NULL; + + /* Check the additional metadata. */ + if (!g_variant_lookup (commit_metadata_v, OSTREE_COMMIT_TIMESTAMP, "t", &commit_timestamp)) + commit_timestamp = 0; /* unknown */ + else + commit_timestamp = GUINT64_FROM_BE (commit_timestamp); + + dt = g_date_time_new_from_unix_utc (commit_timestamp); + + if (dt == NULL) + { + g_debug ("%s: Summary for result ‘%s’ contained commit timestamp %" G_GUINT64_FORMAT " which is too far in the future. Resetting to 0.", + G_STRFUNC, result->remote->name, commit_timestamp); + commit_timestamp = 0; + } + + /* Check and store the commit metadata. */ + commit_metadata = g_hash_table_lookup (commit_metadatas, tmp_checksum); + + if (commit_metadata == NULL) + { + commit_metadata = commit_metadata_new (tmp_checksum, commit_size, + (stored_commit_v != NULL) ? ostree_commit_get_timestamp (stored_commit_v) : 0, + NULL); + g_hash_table_insert (commit_metadatas, commit_metadata->checksum, + commit_metadata /* transfer */); + } + + /* Update the metadata if possible. */ + if (commit_metadata->timestamp == 0) + { + commit_metadata->timestamp = commit_timestamp; + } + else if (commit_timestamp != 0 && commit_metadata->timestamp != commit_timestamp) + { + g_debug ("%s: Summary for result ‘%s’ contained commit timestamp %" G_GUINT64_FORMAT " which did not match existing timestamp %" G_GUINT64_FORMAT ". Ignoring.", + G_STRFUNC, result->remote->name, commit_timestamp, commit_metadata->timestamp); + return FALSE; + } + + if (commit_size != commit_metadata->commit_size) + { + g_debug ("%s: Summary for result ‘%s’ contained commit size %" G_GUINT64_FORMAT "B which did not match existing size %" G_GUINT64_FORMAT "B. Ignoring.", + G_STRFUNC, result->remote->name, commit_size, commit_metadata->commit_size); + return FALSE; + } + + pointer_table_set (refs_and_remotes_table, ref_index, result_index, commit_metadata->checksum); + g_array_append_val (commit_metadata->refs, ref_index); + + g_debug ("%s: Remote ‘%s’ lists ref ‘%s’ mapping to commit ‘%s’.", + G_STRFUNC, result->remote->name, ref_name, commit_metadata->checksum); + } + + return TRUE; +} + +static void +find_remotes_cb (GObject *obj, + GAsyncResult *result, + gpointer user_data) +{ + OstreeRepo *self; + g_autoptr(GTask) task = NULL; + GCancellable *cancellable; + const FindRemotesData *data; + const OstreeCollectionRef * const *refs; + /* FIXME: We currently do nothing with @progress. Comment out to assuage -Wunused-variable */ + /* OstreeAsyncProgress *progress; */ + g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */ + gsize i; + g_autoptr(PointerTable) refs_and_remotes_table = NULL; /* (element-type commit-checksum) */ + g_autoptr(GHashTable) commit_metadatas = NULL; /* (element-type commit-checksum CommitMetadata) */ + g_autoptr(OstreeFetcher) fetcher = NULL; + g_autofree const gchar **ref_to_latest_commit = NULL; /* indexed as @refs; (element-type commit-checksum) */ + g_autofree guint64 *ref_to_latest_timestamp = NULL; /* indexed as @refs; (element-type commit-timestamp) */ + gsize n_refs; + g_autofree char **override_commit_ids = NULL; + g_autoptr(GPtrArray) remotes_to_remove = NULL; /* (element-type OstreeRemote) */ + g_autoptr(GPtrArray) final_results = NULL; /* (element-type OstreeRepoFinderResult) */ + + task = G_TASK (user_data); + self = OSTREE_REPO (g_task_get_source_object (task)); + cancellable = g_task_get_cancellable (task); + data = g_task_get_task_data (task); + + refs = (const OstreeCollectionRef * const *) data->refs; + /* progress = data->progress; */ + + /* Finish finding the remotes. */ + results = ostree_repo_finder_resolve_all_finish (result, &error); + + if (results == NULL) + { + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + if (results->len == 0) + { + g_task_return_pointer (task, g_steal_pointer (&results), (GDestroyNotify) g_ptr_array_unref); + return; + } + + /* Throughout this function, we eliminate invalid results from @results by + * clearing them to %NULL. We cannot remove them from the array, as that messes + * up iteration and stored array indices. Accordingly, we need the free function + * to be %NULL-safe. */ + g_ptr_array_set_free_func (results, (GDestroyNotify) repo_finder_result_free0); + + if (data->options) + { + (void) g_variant_lookup (data->options, "override-commit-ids", "^a&s", &override_commit_ids); + } + + /* FIXME: In future, we also want to pull static delta superblocks in this + * phase, so that we have all the metadata we need for accurate size + * estimation for the actual pull operation. This should check the + * disable-static-deltas option first. */ + + /* Each key must be a pointer to the #CommitMetadata.checksum field of its value. */ + commit_metadatas = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) commit_metadata_free); + + /* X dimension is an index into @refs. Y dimension is an index into @results. + * Each cell stores the commit checksum which that ref resolves to on that + * remote, or %NULL if the remote doesn’t have that ref. */ + n_refs = g_strv_length ((gchar **) refs); /* it’s not a GStrv, but this works */ + refs_and_remotes_table = pointer_table_new (n_refs, results->len); + remotes_to_remove = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_remote_unref); + + /* Fetch and validate the summary file for each result. */ + /* FIXME: All these downloads could be parallelised; that requires the + * ostree_repo_remote_fetch_summary_with_options() API to be async. */ + for (i = 0; i < results->len; i++) + { + OstreeRepoFinderResult *result = g_ptr_array_index (results, i); + g_autoptr(GBytes) summary_bytes = NULL; + g_autoptr(GVariant) summary_v = NULL; + guint64 summary_last_modified; + g_autoptr(GVariant) summary_refs = NULL; + g_autoptr(GVariant) additional_metadata_v = NULL; + g_autofree gchar *summary_collection_id = NULL; + g_autoptr(GVariantIter) summary_collection_map = NULL; + gboolean invalid_result = FALSE; + + /* Add the remote to our internal list of remotes, so other libostree + * API can access it. */ + if (!_ostree_repo_add_remote (self, result->remote)) + g_ptr_array_add (remotes_to_remove, ostree_remote_ref (result->remote)); + + g_debug ("%s: Fetching summary for remote ‘%s’ with keyring ‘%s’.", + G_STRFUNC, result->remote->name, result->remote->keyring); + + /* Download the summary. This will load from the cache if possible. */ + ostree_repo_remote_fetch_summary_with_options (self, + result->remote->name, + NULL, /* no options */ + &summary_bytes, + NULL, + cancellable, + &error); + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto error; + else if (error != NULL) + { + g_debug ("%s: Failed to download summary for result ‘%s’. Ignoring. %s", + G_STRFUNC, result->remote->name, error->message); + g_clear_pointer (&g_ptr_array_index (results, i), (GDestroyNotify) ostree_repo_finder_result_free); + g_clear_error (&error); + continue; + } + else if (summary_bytes == NULL) + { + g_debug ("%s: Failed to download summary for result ‘%s’. Ignoring. %s", + G_STRFUNC, result->remote->name, + "No summary file exists on server"); + g_clear_pointer (&g_ptr_array_index (results, i), (GDestroyNotify) ostree_repo_finder_result_free); + continue; + } + + /* Check the metadata in the summary file, especially whether it contains + * all the @refs we are interested in. */ + summary_v = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE); + + /* Check the summary’s additional metadata and set up @commit_metadata + * and @refs_and_remotes_table with the refs listed in the summary file, + * filtered by the keyring associated with this result and the + * intersection with @refs. */ + additional_metadata_v = g_variant_get_child_value (summary_v, 1); + + if (g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_ID, "s", &summary_collection_id)) + { + summary_refs = g_variant_get_child_value (summary_v, 0); + + if (!find_remotes_process_refs (self, refs, result, i, summary_collection_id, summary_refs, + commit_metadatas, refs_and_remotes_table)) + { + g_clear_pointer (&g_ptr_array_index (results, i), (GDestroyNotify) ostree_repo_finder_result_free); + continue; + } + } + + if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_MAP, "a{sa(s(taya{sv}))}", &summary_collection_map)) + summary_collection_map = NULL; + + while (summary_collection_map != NULL && + g_variant_iter_loop (summary_collection_map, "{s@a(s(taya{sv}))}", &summary_collection_id, &summary_refs)) + { + /* Exclude refs that don't use the associated keyring if this is a + * dynamic remote, by comparing against the collection ID of the + * remote this one inherits from */ + if (result->remote->refspec_name != NULL && + !check_remote_matches_collection_id (self, result->remote->refspec_name, summary_collection_id)) + continue; + + if (!find_remotes_process_refs (self, refs, result, i, summary_collection_id, summary_refs, + commit_metadatas, refs_and_remotes_table)) + { + g_clear_pointer (&g_ptr_array_index (results, i), (GDestroyNotify) ostree_repo_finder_result_free); + invalid_result = TRUE; + break; + } + } + + if (invalid_result) + continue; + + /* Check the summary timestamp. */ + if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_LAST_MODIFIED, "t", &summary_last_modified)) + summary_last_modified = 0; + else + summary_last_modified = GUINT64_FROM_BE (summary_last_modified); + + /* Update the stored result data. Clear the @ref_to_checksum map, since + * it’s been moved to @refs_and_remotes_table and is now potentially out + * of date. */ + g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref); + g_clear_pointer (&result->ref_to_timestamp, g_hash_table_unref); + result->summary_last_modified = summary_last_modified; + } + + /* Fill in any gaps in the metadata for the most recent commits by pulling + * the commit metadata from the remotes. The ‘most recent commits’ are the + * set of head commits pointed to by the refs we just resolved from the + * summary files. */ + GLNX_HASH_TABLE_FOREACH_V (commit_metadatas, CommitMetadata*, commit_metadata) + { + char buf[_OSTREE_LOOSE_PATH_MAX]; + g_autofree gchar *commit_filename = NULL; + g_autoptr(GPtrArray) mirrorlist = NULL; /* (element-type OstreeFetcherURI) */ + g_autoptr(GBytes) commit_bytes = NULL; + g_autoptr(GVariant) commit_v = NULL; + guint64 commit_timestamp; + g_autoptr(GDateTime) dt = NULL; + + /* Already complete? */ + if (commit_metadata->timestamp != 0) + continue; + + _ostree_loose_path (buf, commit_metadata->checksum, OSTREE_OBJECT_TYPE_COMMIT, OSTREE_REPO_MODE_ARCHIVE); + commit_filename = g_build_filename ("objects", buf, NULL); + + /* For each of the remotes whose summary files contain this ref, try + * downloading the commit metadata until we succeed. Since the results are + * in priority order, the most important remotes are tried first. */ + for (i = 0; i < commit_metadata->refs->len; i++) + { + gsize ref_index = g_array_index (commit_metadata->refs, gsize, i); + gsize j; + + for (j = 0; j < results->len; j++) + { + OstreeRepoFinderResult *result = g_ptr_array_index (results, j); + + /* Previous error processing this result? */ + if (result == NULL) + continue; + + if (pointer_table_get (refs_and_remotes_table, ref_index, j) != commit_metadata->checksum) + continue; + + g_autofree gchar *uri = NULL; + g_autoptr(OstreeFetcherURI) fetcher_uri = NULL; + + if (!ostree_repo_remote_get_url (self, result->remote->name, + &uri, &error)) + goto error; + + fetcher_uri = _ostree_fetcher_uri_parse (uri, &error); + if (fetcher_uri == NULL) + goto error; + + fetcher = _ostree_repo_remote_new_fetcher (self, result->remote->name, + TRUE, NULL, &error); + if (fetcher == NULL) + goto error; + + g_debug ("%s: Fetching metadata for commit ‘%s’ from remote ‘%s’.", + G_STRFUNC, commit_metadata->checksum, result->remote->name); + + /* FIXME: Support remotes which have contenturl, mirrorlist, etc. */ + mirrorlist = g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free); + g_ptr_array_add (mirrorlist, g_steal_pointer (&fetcher_uri)); + + if (!_ostree_fetcher_mirrored_request_to_membuf (fetcher, + mirrorlist, + commit_filename, + OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT, + data->n_network_retries, + &commit_bytes, + 0, /* no maximum size */ + cancellable, + &error)) + goto error; + + g_autoptr(OstreeGpgVerifyResult) verify_result = NULL; + + verify_result = ostree_repo_verify_commit_for_remote (self, + commit_metadata->checksum, + result->remote->name, + cancellable, + &error); + if (verify_result == NULL) + { + g_prefix_error (&error, "Commit %s: ", commit_metadata->checksum); + goto error; + } + + if (!ostree_gpg_verify_result_require_valid_signature (verify_result, &error)) + { + g_prefix_error (&error, "Commit %s: ", commit_metadata->checksum); + goto error; + } + + if (commit_bytes != NULL) + break; + } + + if (commit_bytes != NULL) + break; + } + + if (commit_bytes == NULL) + { + g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Metadata not found for commit ‘%s’", commit_metadata->checksum); + goto error; + } + + /* Parse the commit metadata. */ + commit_v = g_variant_new_from_bytes (OSTREE_COMMIT_GVARIANT_FORMAT, + commit_bytes, FALSE); + g_variant_get_child (commit_v, 5, "t", &commit_timestamp); + commit_timestamp = GUINT64_FROM_BE (commit_timestamp); + dt = g_date_time_new_from_unix_utc (commit_timestamp); + + if (dt == NULL) + { + g_debug ("%s: Commit ‘%s’ metadata contained timestamp %" G_GUINT64_FORMAT " which is too far in the future. Resetting to 0.", + G_STRFUNC, commit_metadata->checksum, commit_timestamp); + commit_timestamp = 0; + } + + /* Update the #CommitMetadata. */ + commit_metadata->timestamp = commit_timestamp; + } + + /* Find the latest commit for each ref. This is where we resolve the + * differences between remotes: two remotes could both contain ref R, but one + * remote could be outdated compared to the other, and point to an older + * commit. For each ref, we want to find the most recent commit any remote + * points to for it (unless override-commit-ids was used). + * + * @ref_to_latest_commit is indexed by @ref_index, and its values are the + * latest checksum for each ref. If override-commit-ids was used, + * @ref_to_latest_commit won't be initialized or used. + * + * @ref_to_latest_timestamp is also indexed by @ref_index, and its values are + * the latest timestamp for each ref, when available.*/ + ref_to_latest_commit = g_new0 (const gchar *, n_refs); + ref_to_latest_timestamp = g_new0 (guint64, n_refs); + + for (i = 0; i < n_refs; i++) + { + gsize j; + const gchar *latest_checksum = NULL; + const CommitMetadata *latest_commit_metadata = NULL; + g_autofree gchar *latest_commit_timestamp_str = NULL; + + if (override_commit_ids) + { + g_debug ("%s: Using specified commit ‘%s’ for ref (%s, %s).", + G_STRFUNC, override_commit_ids[i], refs[i]->collection_id, refs[i]->ref_name); + continue; + } + + for (j = 0; j < results->len; j++) + { + const CommitMetadata *candidate_commit_metadata; + const gchar *candidate_checksum; + + candidate_checksum = pointer_table_get (refs_and_remotes_table, i, j); + + if (candidate_checksum == NULL) + continue; + + candidate_commit_metadata = g_hash_table_lookup (commit_metadatas, candidate_checksum); + g_assert (candidate_commit_metadata != NULL); + + if (latest_commit_metadata == NULL || + candidate_commit_metadata->timestamp > latest_commit_metadata->timestamp) + { + latest_checksum = candidate_checksum; + latest_commit_metadata = candidate_commit_metadata; + } + } + + /* @latest_checksum could be %NULL here if there was an error downloading + * the summary or commit metadata files above. */ + ref_to_latest_commit[i] = latest_checksum; + + if (latest_checksum != NULL && latest_commit_metadata != NULL) + ref_to_latest_timestamp[i] = latest_commit_metadata->timestamp; + else + ref_to_latest_timestamp[i] = 0; + + if (latest_commit_metadata != NULL) + { + latest_commit_timestamp_str = uint64_secs_to_iso8601 (latest_commit_metadata->timestamp); + g_debug ("%s: Latest commit for ref (%s, %s) across all remotes is ‘%s’ with timestamp %s.", + G_STRFUNC, refs[i]->collection_id, refs[i]->ref_name, + latest_checksum, latest_commit_timestamp_str); + } + else + { + g_debug ("%s: Latest commit for ref (%s, %s) is unknown due to failure to download metadata.", + G_STRFUNC, refs[i]->collection_id, refs[i]->ref_name); + } + } + + /* Recombine @commit_metadatas and @results so that each + * #OstreeRepoFinderResult.refs lists the refs for which that remote has the + * latest commits (i.e. it’s not out of date compared to some other remote). */ + final_results = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_repo_finder_result_free); + + for (i = 0; i < results->len; i++) + { + OstreeRepoFinderResult *result = g_ptr_array_index (results, i); + g_autoptr(GHashTable) validated_ref_to_checksum = NULL; /* (element-type OstreeCollectionRef utf8) */ + g_autoptr(GHashTable) validated_ref_to_timestamp = NULL; /* (element-type OstreeCollectionRef guint64) */ + gsize j, n_latest_refs; + + /* Previous error processing this result? */ + if (result == NULL) + continue; + + /* Map of refs to checksums provided by this result. The checksums should + * be %NULL for each ref unless this result provides the latest checksum. */ + validated_ref_to_checksum = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + (GDestroyNotify) ostree_collection_ref_free, + g_free); + + validated_ref_to_timestamp = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + (GDestroyNotify) ostree_collection_ref_free, + g_free); + if (override_commit_ids) + { + for (j = 0; refs[j] != NULL; j++) + { + guint64 *timestamp_ptr; + + g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]), + g_strdup (override_commit_ids[j])); + + timestamp_ptr = g_malloc (sizeof (guint64)); + *timestamp_ptr = 0; + g_hash_table_insert (validated_ref_to_timestamp, ostree_collection_ref_dup (refs[j]), + timestamp_ptr); + } + } + else + { + n_latest_refs = 0; + + for (j = 0; refs[j] != NULL; j++) + { + const gchar *latest_commit_for_ref = ref_to_latest_commit[j]; + guint64 *timestamp_ptr; + + if (pointer_table_get (refs_and_remotes_table, j, i) != latest_commit_for_ref) + latest_commit_for_ref = NULL; + if (latest_commit_for_ref != NULL) + n_latest_refs++; + + g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]), + g_strdup (latest_commit_for_ref)); + + timestamp_ptr = g_malloc (sizeof (guint64)); + if (latest_commit_for_ref != NULL) + *timestamp_ptr = GUINT64_TO_BE (ref_to_latest_timestamp[j]); + else + *timestamp_ptr = 0; + g_hash_table_insert (validated_ref_to_timestamp, ostree_collection_ref_dup (refs[j]), + timestamp_ptr); + } + + if (n_latest_refs == 0) + { + g_debug ("%s: Omitting remote ‘%s’ from results as none of its refs are new enough.", + G_STRFUNC, result->remote->name); + ostree_repo_finder_result_free (g_steal_pointer (&g_ptr_array_index (results, i))); + continue; + } + } + + result->ref_to_checksum = g_steal_pointer (&validated_ref_to_checksum); + result->ref_to_timestamp = g_steal_pointer (&validated_ref_to_timestamp); + g_ptr_array_add (final_results, g_steal_pointer (&g_ptr_array_index (results, i))); + } + + /* Ensure the updated results are still in priority order. */ + g_ptr_array_sort (final_results, sort_results_cb); + + /* Remove the remotes we temporarily added. + * FIXME: It would be so much better if we could pass #OstreeRemote pointers + * around internally, to avoid serialising on the global table of them. */ + for (i = 0; i < remotes_to_remove->len; i++) + { + OstreeRemote *remote = g_ptr_array_index (remotes_to_remove, i); + _ostree_repo_remove_remote (self, remote); + } + + g_task_return_pointer (task, g_steal_pointer (&final_results), (GDestroyNotify) g_ptr_array_unref); + + return; + +error: + /* Remove the remotes we temporarily added. */ + for (i = 0; i < remotes_to_remove->len; i++) + { + OstreeRemote *remote = g_ptr_array_index (remotes_to_remove, i); + _ostree_repo_remove_remote (self, remote); + } + + g_task_return_error (task, g_steal_pointer (&error)); +} + +/** + * ostree_repo_find_remotes_finish: + * @self: an #OstreeRepo + * @result: the asynchronous result + * @error: return location for a #GError, or %NULL + * + * Finish an asynchronous pull operation started with + * ostree_repo_find_remotes_async(). + * + * Returns: (transfer full) (array zero-terminated=1): a potentially empty array + * of #OstreeRepoFinderResults, followed by a %NULL terminator element; or + * %NULL on error + * Since: 2018.6 + */ +OstreeRepoFinderResult ** +ostree_repo_find_remotes_finish (OstreeRepo *self, + GAsyncResult *result, + GError **error) +{ + g_autoptr(GPtrArray) results = NULL; + + g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); + g_return_val_if_fail (g_task_is_valid (result, self), NULL); + g_return_val_if_fail (g_async_result_is_tagged (result, ostree_repo_find_remotes_async), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + results = g_task_propagate_pointer (G_TASK (result), error); + + if (results != NULL) + { + g_ptr_array_add (results, NULL); /* NULL terminator */ + return (OstreeRepoFinderResult **) g_ptr_array_free (g_steal_pointer (&results), FALSE); + } + else + return NULL; +} + +static void +copy_option (GVariantDict *master_options, + GVariantDict *slave_options, + const gchar *key, + const GVariantType *expected_type) +{ + g_autoptr(GVariant) option_v = g_variant_dict_lookup_value (master_options, key, expected_type); + if (option_v != NULL) + g_variant_dict_insert_value (slave_options, key, option_v); +} + +/** + * ostree_repo_pull_from_remotes_async: + * @self: an #OstreeRepo + * @results: (array zero-terminated=1): %NULL-terminated array of remotes to + * pull from, including the refs to pull from each + * @options: (nullable): A GVariant `a{sv}` with an extensible set of flags + * @progress: (nullable): an #OstreeAsyncProgress to update with the operation’s + * progress, or %NULL + * @cancellable: (nullable): a #GCancellable, or %NULL + * @callback: asynchronous completion callback + * @user_data: data to pass to @callback + * + * Pull refs from multiple remotes which have been found using + * ostree_repo_find_remotes_async(). + * + * @results are expected to be in priority order, with the best remotes to pull + * from listed first. ostree_repo_pull_from_remotes_async() will generally pull + * from the remotes in order, but may parallelise its downloads. + * + * If an error is encountered when pulling from a given remote, that remote will + * be ignored and another will be tried instead. If any refs have not been + * downloaded successfully after all remotes have been tried, %G_IO_ERROR_FAILED + * will be returned. The results of any successful downloads will remain cached + * in the local repository. + * + * If @cancellable is cancelled, %G_IO_ERROR_CANCELLED will be returned + * immediately. The results of any successfully completed downloads at that + * point will remain cached in the local repository. + * + * GPG verification of commits will be used unconditionally. + * + * The following @options are currently defined: + * + * * `flags` (`i`): #OstreeRepoPullFlags to apply to the pull operation + * * `inherit-transaction` (`b`): %TRUE to inherit an ongoing transaction on + * the #OstreeRepo, rather than encapsulating the pull in a new one + * * `depth` (`i`): How far in the history to traverse; default is 0, -1 means infinite + * * `disable-static-deltas` (`b`): Do not use static deltas + * * `http-headers` (`a(ss)`): Additional headers to add to all HTTP requests + * * `subdirs` (`as`): Pull just these subdirectories + * * `update-frequency` (`u`): Frequency to call the async progress callback in + * milliseconds, if any; only values higher than 0 are valid + * * `append-user-agent` (`s`): Additional string to append to the user agent + * * `n-network-retries` (`u`): Number of times to retry each download on receiving + * a transient network error, such as a socket timeout; default is 5, 0 + * means return errors without retrying. Since: 2018.6 + * * `ref-keyring-map` (`a(sss)`): Array of (collection ID, ref name, keyring + * remote name) tuples specifying which remote's keyring should be used when + * doing GPG verification of each collection-ref. This is useful to prevent a + * remote from serving malicious updates to refs which did not originate from + * it. This can be a subset or superset of the refs being pulled; any ref + * not being pulled will be ignored and any ref without a keyring remote + * will be verified with the keyring of the remote being pulled from. + * Since: 2019.2 + * + * Since: 2018.6 + */ +void +ostree_repo_pull_from_remotes_async (OstreeRepo *self, + const OstreeRepoFinderResult * const *results, + GVariant *options, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (OSTREE_IS_REPO (self)); + g_return_if_fail (results != NULL && results[0] != NULL); + g_return_if_fail (options == NULL || g_variant_is_of_type (options, G_VARIANT_TYPE ("a{sv}"))); + g_return_if_fail (progress == NULL || OSTREE_IS_ASYNC_PROGRESS (progress)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + g_autoptr(GTask) task = NULL; + g_autoptr(GHashTable) refs_pulled = NULL; /* (element-type OstreeCollectionRef gboolean) */ + gsize i, j; + g_autoptr(GString) refs_unpulled_string = NULL; + g_autoptr(GError) local_error = NULL; + g_auto(GVariantDict) options_dict = OT_VARIANT_BUILDER_INITIALIZER; + OstreeRepoPullFlags flags; + gboolean inherit_transaction; + + /* Set up a task for the whole operation. */ + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, ostree_repo_pull_from_remotes_async); + + /* Keep track of the set of refs we’ve pulled already. Value is %TRUE if the + * ref has been pulled; %FALSE if it has not. */ + refs_pulled = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, NULL, NULL); + + g_variant_dict_init (&options_dict, options); + + if (!g_variant_dict_lookup (&options_dict, "flags", "i", &flags)) + flags = OSTREE_REPO_PULL_FLAGS_NONE; + if (!g_variant_dict_lookup (&options_dict, "inherit-transaction", "b", &inherit_transaction)) + inherit_transaction = FALSE; + + /* Run all the local pull operations in a single overall transaction. */ + if (!inherit_transaction && + !ostree_repo_prepare_transaction (self, NULL, cancellable, &local_error)) + { + g_task_return_error (task, g_steal_pointer (&local_error)); + return; + } + + /* FIXME: Rework this code to pull in parallel where possible. At the moment + * we expect the (i == 0) iteration will do all the work (all the refs) and + * subsequent iterations are only there in case of error. + * + * The code is currently all synchronous, too. Making it asynchronous requires + * the underlying pull code to be asynchronous. */ + for (i = 0; results[i] != NULL; i++) + { + const OstreeRepoFinderResult *result = results[i]; + + g_autoptr(GString) refs_to_pull_str = NULL; + g_autoptr(GPtrArray) refs_to_pull = NULL; /* (element-type OstreeCollectionRef) */ + g_auto(GVariantBuilder) refs_to_pull_builder = OT_VARIANT_BUILDER_INITIALIZER; + g_auto(GVariantDict) local_options_dict = OT_VARIANT_BUILDER_INITIALIZER; + g_autoptr(GVariant) local_options = NULL; + gboolean remove_remote; + + refs_to_pull = g_ptr_array_new_with_free_func (NULL); + refs_to_pull_str = g_string_new (""); + g_variant_builder_init (&refs_to_pull_builder, G_VARIANT_TYPE ("a(sss)")); + + GLNX_HASH_TABLE_FOREACH_KV (result->ref_to_checksum, const OstreeCollectionRef*, ref, + const char*, checksum) + { + if (checksum != NULL && + !GPOINTER_TO_INT (g_hash_table_lookup (refs_pulled, ref))) + { + g_ptr_array_add (refs_to_pull, (gpointer) ref); + g_variant_builder_add (&refs_to_pull_builder, "(sss)", + ref->collection_id, ref->ref_name, checksum); + + if (refs_to_pull_str->len > 0) + g_string_append (refs_to_pull_str, ", "); + g_string_append_printf (refs_to_pull_str, "(%s, %s)", + ref->collection_id, ref->ref_name); + } + } + + if (refs_to_pull->len == 0) + { + g_debug ("Ignoring remote ‘%s’ as it has no relevant refs or they " + "have already been pulled.", + result->remote->name); + continue; + } + + /* NULL terminators. */ + g_ptr_array_add (refs_to_pull, NULL); + + g_debug ("Pulling from remote ‘%s’: %s", + result->remote->name, refs_to_pull_str->str); + + /* Set up the pull options. */ + g_variant_dict_init (&local_options_dict, NULL); + + g_variant_dict_insert (&local_options_dict, "flags", "i", OSTREE_REPO_PULL_FLAGS_UNTRUSTED | flags); + g_variant_dict_insert_value (&local_options_dict, "collection-refs", g_variant_builder_end (&refs_to_pull_builder)); +#ifndef OSTREE_DISABLE_GPGME + g_variant_dict_insert (&local_options_dict, "gpg-verify", "b", TRUE); +#else + g_variant_dict_insert (&local_options_dict, "gpg-verify", "b", FALSE); +#endif /* OSTREE_DISABLE_GPGME */ + g_variant_dict_insert (&local_options_dict, "gpg-verify-summary", "b", FALSE); + g_variant_dict_insert (&local_options_dict, "sign-verify", "b", FALSE); + g_variant_dict_insert (&local_options_dict, "sign-verify-summary", "b", FALSE); + g_variant_dict_insert (&local_options_dict, "inherit-transaction", "b", TRUE); + if (result->remote->refspec_name != NULL) + g_variant_dict_insert (&local_options_dict, "override-remote-name", "s", result->remote->refspec_name); + copy_option (&options_dict, &local_options_dict, "depth", G_VARIANT_TYPE ("i")); + copy_option (&options_dict, &local_options_dict, "disable-static-deltas", G_VARIANT_TYPE ("b")); + copy_option (&options_dict, &local_options_dict, "http-headers", G_VARIANT_TYPE ("a(ss)")); + copy_option (&options_dict, &local_options_dict, "subdirs", G_VARIANT_TYPE ("as")); + copy_option (&options_dict, &local_options_dict, "update-frequency", G_VARIANT_TYPE ("u")); + copy_option (&options_dict, &local_options_dict, "append-user-agent", G_VARIANT_TYPE ("s")); + copy_option (&options_dict, &local_options_dict, "n-network-retries", G_VARIANT_TYPE ("u")); + copy_option (&options_dict, &local_options_dict, "ref-keyring-map", G_VARIANT_TYPE ("a(sss)")); + + local_options = g_variant_dict_end (&local_options_dict); + + /* FIXME: We do nothing useful with @progress at the moment. */ + remove_remote = !_ostree_repo_add_remote (self, result->remote); + ostree_repo_pull_with_options (self, result->remote->name, local_options, + progress, cancellable, &local_error); + if (remove_remote) + _ostree_repo_remove_remote (self, result->remote); + + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + if (!inherit_transaction) + ostree_repo_abort_transaction (self, NULL, NULL); + g_task_return_error (task, g_steal_pointer (&local_error)); + return; + } + + for (j = 0; refs_to_pull->pdata[j] != NULL; j++) + g_hash_table_replace (refs_pulled, refs_to_pull->pdata[j], + GINT_TO_POINTER (local_error == NULL)); + + if (local_error != NULL) + { + g_debug ("Failed to pull refs from ‘%s’: %s", + result->remote->name, local_error->message); + g_clear_error (&local_error); + continue; + } + else + { + g_debug ("Pulled refs from ‘%s’.", result->remote->name); + } + } + + /* Commit the transaction. */ + if (!inherit_transaction && + !ostree_repo_commit_transaction (self, NULL, cancellable, &local_error)) + { + g_task_return_error (task, g_steal_pointer (&local_error)); + return; + } + + /* Any refs left un-downloaded? If so, we’ve failed. */ + GLNX_HASH_TABLE_FOREACH_KV (refs_pulled, const OstreeCollectionRef*, ref, + gpointer, is_pulled_pointer) + { + gboolean is_pulled = GPOINTER_TO_INT (is_pulled_pointer); + + if (is_pulled) + continue; + + if (refs_unpulled_string == NULL) + refs_unpulled_string = g_string_new (""); + else + g_string_append (refs_unpulled_string, ", "); + + g_string_append_printf (refs_unpulled_string, "(%s, %s)", + ref->collection_id, ref->ref_name); + } + + if (refs_unpulled_string != NULL) + { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to pull some refs from the remotes: %s", + refs_unpulled_string->str); + return; + } + + g_task_return_boolean (task, TRUE); +} + +/** + * ostree_repo_pull_from_remotes_finish: + * @self: an #OstreeRepo + * @result: the asynchronous result + * @error: return location for a #GError, or %NULL + * + * Finish an asynchronous pull operation started with + * ostree_repo_pull_from_remotes_async(). + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: 2018.6 + */ +gboolean +ostree_repo_pull_from_remotes_finish (OstreeRepo *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_async_result_is_tagged (result, ostree_repo_pull_from_remotes_async), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +/** + * ostree_repo_remote_fetch_summary_with_options: + * @self: Self + * @name: name of a remote + * @options: (nullable): A GVariant a{sv} with an extensible set of flags + * @out_summary: (out) (optional): return location for raw summary data, or + * %NULL + * @out_signatures: (out) (optional): return location for raw summary + * signature data, or %NULL + * @cancellable: a #GCancellable + * @error: a #GError + * + * Like ostree_repo_remote_fetch_summary(), but supports an extensible set of flags. + * The following are currently defined: + * + * - override-url (s): Fetch summary from this URL if remote specifies no metalink in options + * - http-headers (a(ss)): Additional headers to add to all HTTP requests + * - append-user-agent (s): Additional string to append to the user agent + * - n-network-retries (u): Number of times to retry each download on receiving + * a transient network error, such as a socket timeout; default is 5, 0 + * means return errors without retrying + * + * Returns: %TRUE on success, %FALSE on failure + * + * Since: 2016.6 + */ +gboolean +ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self, + const char *name, + GVariant *options, + GBytes **out_summary, + GBytes **out_signatures, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *metalink_url_string = NULL; + g_autoptr(GBytes) summary = NULL; + g_autoptr(GBytes) signatures = NULL; + gboolean gpg_verify_summary; + g_autoptr(GPtrArray) signapi_summary_verifiers = NULL; + gboolean ret = FALSE; + gboolean summary_is_from_cache; + + g_return_val_if_fail (OSTREE_REPO (self), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + if (!ostree_repo_get_remote_option (self, name, "metalink", NULL, + &metalink_url_string, error)) + goto out; + + if (!repo_remote_fetch_summary (self, + name, + metalink_url_string, + options, + &summary, + &signatures, + &summary_is_from_cache, + cancellable, + error)) + goto out; + + if (!ostree_repo_remote_get_gpg_verify_summary (self, name, &gpg_verify_summary, error)) + goto out; + + if (gpg_verify_summary) + { + if (summary == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "GPG verification enabled, but no summary found (check that the configured URL in remote config is correct)"); + goto out; + } + + if (signatures == NULL) + { + g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, + "GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)"); + goto out; + } + + /* Verify any summary signatures. */ + if (summary != NULL && signatures != NULL) + { + g_autoptr(OstreeGpgVerifyResult) result = NULL; + + result = ostree_repo_verify_summary (self, + name, + summary, + signatures, + cancellable, + error); + if (!ostree_gpg_verify_result_require_valid_signature (result, error)) + goto out; + } + } + + if (!_signapi_init_for_remote (self, name, NULL, + &signapi_summary_verifiers, + error)) + goto out; + + if (signapi_summary_verifiers) + { + if (summary == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Signature verification enabled, but no summary found (check that the configured URL in remote config is correct)"); + goto out; + } + + if (signatures == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Signature verification enabled, but no summary signatures found (use sign-verify-summary=false in remote config to disable)"); + goto out; + } + + /* Verify any summary signatures. */ + if (summary != NULL && signatures != NULL) + { + g_autoptr(GVariant) sig_variant = NULL; + + sig_variant = g_variant_new_from_bytes (OSTREE_SUMMARY_SIG_GVARIANT_FORMAT, + signatures, FALSE); + + if (!_sign_verify_for_remote (signapi_summary_verifiers, summary, sig_variant, NULL, error)) + goto out; + } + } + + if (!summary_is_from_cache && summary && signatures) + { + g_autoptr(GError) temp_error = NULL; + + if (!_ostree_repo_cache_summary (self, + name, + summary, + signatures, + cancellable, + &temp_error)) + { + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) + g_debug ("No permissions to save summary cache"); + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + goto out; + } + } + } + + if (out_summary != NULL) + *out_summary = g_steal_pointer (&summary); + + if (out_signatures != NULL) + *out_signatures = g_steal_pointer (&signatures); + + ret = TRUE; + +out: + return ret; +} + +#else /* HAVE_LIBCURL_OR_LIBSOUP */ + +gboolean +ostree_repo_pull_with_options (OstreeRepo *self, + const char *remote_name_or_baseurl, + GVariant *options, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GError **error) +{ + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree was built without libsoup or libcurl, and cannot fetch over HTTP"); + return FALSE; +} + +gboolean +ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self, + const char *name, + GVariant *options, + GBytes **out_summary, + GBytes **out_signatures, + GCancellable *cancellable, + GError **error) +{ + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree was built without libsoup or libcurl, and cannot fetch over HTTP"); + return FALSE; +} + +void +ostree_repo_find_remotes_async (OstreeRepo *self, + const OstreeCollectionRef * const *refs, + GVariant *options, + OstreeRepoFinder **finders, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (OSTREE_IS_REPO (self)); + + g_task_report_new_error (self, callback, user_data, ostree_repo_find_remotes_async, + G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree was built without libsoup or libcurl, and cannot fetch over HTTP"); +} + +OstreeRepoFinderResult ** +ostree_repo_find_remotes_finish (OstreeRepo *self, + GAsyncResult *result, + GError **error) +{ + g_autoptr(GPtrArray) results = NULL; + + g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); + g_return_val_if_fail (g_task_is_valid (result, self), NULL); + g_return_val_if_fail (g_async_result_is_tagged (result, ostree_repo_find_remotes_async), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + results = g_task_propagate_pointer (G_TASK (result), error); + g_assert (results == NULL); + return NULL; +} + +void +ostree_repo_pull_from_remotes_async (OstreeRepo *self, + const OstreeRepoFinderResult * const *results, + GVariant *options, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (OSTREE_IS_REPO (self)); + + g_task_report_new_error (self, callback, user_data, ostree_repo_find_remotes_async, + G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree was built without libsoup or libcurl, and cannot fetch over HTTP"); +} + +gboolean +ostree_repo_pull_from_remotes_finish (OstreeRepo *self, + GAsyncResult *result, + GError **error) +{ + gboolean success; + + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_async_result_is_tagged (result, ostree_repo_pull_from_remotes_async), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + success = g_task_propagate_boolean (G_TASK (result), error); + g_assert (!success); + return FALSE; +} + +#endif /* HAVE_LIBCURL_OR_LIBSOUP */ diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c new file mode 100644 index 0000000..d1d679b --- /dev/null +++ b/src/libostree/ostree-repo-refs.c @@ -0,0 +1,1398 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-core-private.h" +#include "ostree-repo-private.h" +#include "otutil.h" +#include "ot-fs-utils.h" + +/* This is polymorphic in @collection_id: if non-%NULL, @refs will be treated as of + * type OstreeCollectionRef ↦ checksum. Otherwise, it will be treated as of type + * refspec ↦ checksum. */ +static gboolean +add_ref_to_set (const char *remote, + const char *collection_id, + int base_fd, + const char *path, + GHashTable *refs, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (remote == NULL || collection_id == NULL, FALSE); + + gsize len; + char *contents = glnx_file_get_contents_utf8_at (base_fd, path, &len, cancellable, error); + if (!contents) + return FALSE; + + g_strchomp (contents); + + if (collection_id == NULL) + { + g_autoptr(GString) refname = g_string_new (""); + if (remote) + { + g_string_append (refname, remote); + g_string_append_c (refname, ':'); + } + g_string_append (refname, path); + g_hash_table_insert (refs, g_string_free (g_steal_pointer (&refname), FALSE), contents); + } + else + { + g_hash_table_insert (refs, ostree_collection_ref_new (collection_id, path), contents); + } + + return TRUE; +} + +static gboolean +write_checksum_file_at (OstreeRepo *self, + int dfd, + const char *name, + const char *sha256, + GCancellable *cancellable, + GError **error) +{ + if (!ostree_validate_checksum_string (sha256, error)) + return FALSE; + + if (ostree_validate_checksum_string (name, NULL)) + return glnx_throw (error, "Rev name '%s' looks like a checksum", name); + + if (!*name) + return glnx_throw (error, "Invalid empty ref name"); + + const char *lastslash = strrchr (name, '/'); + + if (lastslash) + { + char *parent = strdupa (name); + parent[lastslash - name] = '\0'; + + if (!glnx_shutil_mkdir_p_at (dfd, parent, 0777, cancellable, error)) + return FALSE; + } + + { + size_t l = strlen (sha256); + char *bufnl = alloca (l + 2); + g_autoptr(GError) temp_error = NULL; + + memcpy (bufnl, sha256, l); + bufnl[l] = '\n'; + bufnl[l+1] = '\0'; + + if (!_ostree_repo_file_replace_contents (self, dfd, name, (guint8*)bufnl, l + 1, + cancellable, &temp_error)) + { + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) + { + g_autoptr(GHashTable) refs = NULL; + GHashTableIter hashiter; + gpointer hashkey, hashvalue; + + g_clear_error (&temp_error); + + /* FIXME: Conflict detection needs to be extended to collection–refs + * using ostree_repo_list_collection_refs(). */ + if (!ostree_repo_list_refs (self, name, &refs, cancellable, error)) + return FALSE; + + g_hash_table_iter_init (&hashiter, refs); + + while ((g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))) + { + if (strcmp (name, (char *)hashkey) != 0) + return glnx_throw (error, "Conflict: %s exists under %s when attempting write", (char*)hashkey, name); + } + + if (!glnx_shutil_rm_rf_at (dfd, name, cancellable, error)) + return FALSE; + + if (!_ostree_repo_file_replace_contents (self, dfd, name, (guint8*)bufnl, l + 1, + cancellable, error)) + return FALSE; + } + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + return FALSE; + } + } + } + + return TRUE; +} + +static gboolean +find_ref_in_remotes (OstreeRepo *self, + const char *rev, + int *out_fd, + GError **error) +{ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + glnx_autofd int ret_fd = -1; + + if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent = NULL; + glnx_autofd int remote_dfd = -1; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, NULL, error)) + return FALSE; + if (dent == NULL) + break; + + if (dent->d_type != DT_DIR) + continue; + + if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error)) + return FALSE; + + if (!ot_openat_ignore_enoent (remote_dfd, rev, &ret_fd, error)) + return FALSE; + + if (ret_fd != -1) + break; + } + + *out_fd = ret_fd; ret_fd = -1; + return TRUE; +} + +static gboolean +resolve_refspec (OstreeRepo *self, + const char *remote, + const char *ref, + gboolean allow_noent, + gboolean fallback_remote, + char **out_rev, + GError **error); + +static gboolean +resolve_refspec_fallback (OstreeRepo *self, + const char *remote, + const char *ref, + gboolean allow_noent, + gboolean fallback_remote, + char **out_rev, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *ret_rev = NULL; + + if (self->parent_repo) + { + if (!resolve_refspec (self->parent_repo, remote, ref, allow_noent, + fallback_remote, &ret_rev, error)) + return FALSE; + } + else if (!allow_noent) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Refspec '%s%s%s' not found", + remote ? remote : "", + remote ? ":" : "", + ref); + return FALSE; + } + + ot_transfer_out_value (out_rev, &ret_rev); + return TRUE; +} + +static gboolean +resolve_refspec (OstreeRepo *self, + const char *remote, + const char *ref, + gboolean allow_noent, + gboolean fallback_remote, + char **out_rev, + GError **error) +{ + __attribute__((unused)) GCancellable *cancellable = NULL; + g_autofree char *ret_rev = NULL; + glnx_autofd int target_fd = -1; + + g_return_val_if_fail (ref != NULL, FALSE); + + /* We intentionally don't allow a ref that looks like a checksum */ + if (ostree_validate_checksum_string (ref, NULL)) + { + ret_rev = g_strdup (ref); + } + else if (self->in_transaction) + { + const char *refspec; + + if (remote != NULL) + refspec = glnx_strjoina (remote, ":", ref); + else + refspec = ref; + + g_mutex_lock (&self->txn_lock); + if (self->txn.refs) + ret_rev = g_strdup (g_hash_table_lookup (self->txn.refs, refspec)); + g_mutex_unlock (&self->txn_lock); + } + + if (ret_rev != NULL) + { + ot_transfer_out_value (out_rev, &ret_rev); + return TRUE; + } + + if (remote != NULL) + { + const char *remote_ref = glnx_strjoina ("refs/remotes/", remote, "/", ref); + + if (!ot_openat_ignore_enoent (self->repo_dir_fd, remote_ref, &target_fd, error)) + return FALSE; + } + else + { + const char *local_ref = glnx_strjoina ("refs/heads/", ref); + + if (!ot_openat_ignore_enoent (self->repo_dir_fd, local_ref, &target_fd, error)) + return FALSE; + + if (target_fd == -1 && fallback_remote) + { + local_ref = glnx_strjoina ("refs/remotes/", ref); + + if (!ot_openat_ignore_enoent (self->repo_dir_fd, local_ref, &target_fd, error)) + return FALSE; + + if (target_fd == -1) + { + if (!find_ref_in_remotes (self, ref, &target_fd, error)) + return FALSE; + } + } + } + + if (target_fd != -1) + { + ret_rev = glnx_fd_readall_utf8 (target_fd, NULL, NULL, error); + if (!ret_rev) + { + g_prefix_error (error, "Couldn't open ref '%s': ", ref); + return FALSE; + } + + g_strchomp (ret_rev); + if (!ostree_validate_checksum_string (ret_rev, error)) + return FALSE; + } + else + { + if (!resolve_refspec_fallback (self, remote, ref, allow_noent, fallback_remote, + &ret_rev, cancellable, error)) + return FALSE; + } + + ot_transfer_out_value (out_rev, &ret_rev); + return TRUE; +} + +/** + * ostree_repo_resolve_partial_checksum: + * @self: Repo + * @refspec: A refspec + * @full_checksum (out) (transfer full): A full checksum corresponding to the truncated ref given + * @error: Error + * + * Look up the existing refspec checksums. If the given ref is a unique truncated beginning + * of a valid checksum it will return that checksum in the parameter @full_checksum + */ +static gboolean +ostree_repo_resolve_partial_checksum (OstreeRepo *self, + const char *refspec, + char **full_checksum, + GError **error) +{ + static const char hexchars[] = "0123456789abcdef"; + g_autofree char *ret_rev = NULL; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* If the input is longer than OSTREE_SHA256_STRING_LEN chars or contains non-hex chars, + don't bother looking for it as an object */ + const gsize off = strspn (refspec, hexchars); + if (off > OSTREE_SHA256_STRING_LEN || refspec[off] != '\0') + return TRUE; + + /* this looks through all objects and adds them to the ref_list if: + a) they are a commit object AND + b) the obj checksum starts with the partual checksum defined by "refspec" */ + g_autoptr(GHashTable) ref_list = NULL; + if (!ostree_repo_list_commit_objects_starting_with (self, refspec, &ref_list, NULL, error)) + return FALSE; + + guint length = g_hash_table_size (ref_list); + + GHashTableIter hashiter; + gpointer key, value; + GVariant *first_commit = NULL; + g_hash_table_iter_init (&hashiter, ref_list); + if (g_hash_table_iter_next (&hashiter, &key, &value)) + first_commit = (GVariant*) key; + + OstreeObjectType objtype; + const char *checksum = NULL; + if (first_commit) + ostree_object_name_deserialize (first_commit, &checksum, &objtype); + + /* length more than one - multiple commits match partial refspec: is not unique */ + if (length > 1) + return glnx_throw (error, "Refspec %s not unique", refspec); + /* length is 1 - a single matching commit gives us our revision */ + else if (length == 1) + ret_rev = g_strdup (checksum); + + /* Note: if length is 0, then code will return TRUE + because there is no error, but it will return full_checksum = NULL + to signal to continue parsing */ + + ot_transfer_out_value (full_checksum, &ret_rev); + return TRUE; +} + +static gboolean +_ostree_repo_resolve_rev_internal (OstreeRepo *self, + const char *refspec, + gboolean allow_noent, + gboolean fallback_remote, + char **out_rev, + GError **error) +{ + g_autofree char *ret_rev = NULL; + + g_return_val_if_fail (refspec != NULL, FALSE); + + if (ostree_validate_checksum_string (refspec, NULL)) + { + ret_rev = g_strdup (refspec); + } + + else if (!ostree_repo_resolve_partial_checksum (self, refspec, &ret_rev, error)) + return FALSE; + + if (!ret_rev) + { + if (error != NULL && *error != NULL) + return FALSE; + + if (g_str_has_suffix (refspec, "^")) + { + g_autofree char *parent_refspec = NULL; + g_autofree char *parent_rev = NULL; + g_autoptr(GVariant) commit = NULL; + + parent_refspec = g_strdup (refspec); + parent_refspec[strlen(parent_refspec) - 1] = '\0'; + + if (!ostree_repo_resolve_rev (self, parent_refspec, allow_noent, &parent_rev, error)) + return FALSE; + + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, parent_rev, + &commit, error)) + return FALSE; + + if (!(ret_rev = ostree_commit_get_parent (commit))) + return glnx_throw (error, "Commit %s has no parent", parent_rev); + } + else + { + g_autofree char *remote = NULL; + g_autofree char *ref = NULL; + + if (!ostree_parse_refspec (refspec, &remote, &ref, error)) + return FALSE; + + if (!resolve_refspec (self, remote, ref, allow_noent, + fallback_remote, &ret_rev, error)) + return FALSE; + } + } + + ot_transfer_out_value (out_rev, &ret_rev); + return TRUE; +} + +/** + * ostree_repo_resolve_rev: + * @self: Repo + * @refspec: A refspec + * @allow_noent: Do not throw an error if refspec does not exist + * @out_rev: (out) (transfer full): A checksum,or %NULL if @allow_noent is true and it does not exist + * @error: Error + * + * Look up the given refspec, returning the checksum it references in + * the parameter @out_rev. Will fall back on remote directory if cannot + * find the given refspec in local. + */ +gboolean +ostree_repo_resolve_rev (OstreeRepo *self, + const char *refspec, + gboolean allow_noent, + char **out_rev, + GError **error) +{ + return _ostree_repo_resolve_rev_internal (self, refspec, allow_noent, TRUE, out_rev, error); +} + +/** + * ostree_repo_resolve_rev_ext: + * @self: Repo + * @refspec: A refspec + * @allow_noent: Do not throw an error if refspec does not exist + * @flags: Options controlling behavior + * @out_rev: (out) (transfer full): A checksum,or %NULL if @allow_noent is true and it does not exist + * @error: Error + * + * Look up the given refspec, returning the checksum it references in + * the parameter @out_rev. Differently from ostree_repo_resolve_rev(), + * this will not fall back to searching through remote repos if a + * local ref is specified but not found. + * + * The flag %OSTREE_REPO_RESOLVE_REV_EXT_LOCAL_ONLY is implied so + * using it has no effect. + * + * Since: 2016.7 + */ +gboolean +ostree_repo_resolve_rev_ext (OstreeRepo *self, + const char *refspec, + gboolean allow_noent, + OstreeRepoResolveRevExtFlags flags, + char **out_rev, + GError **error) +{ + return _ostree_repo_resolve_rev_internal (self, refspec, allow_noent, FALSE, out_rev, error); +} + +/** + * ostree_repo_resolve_collection_ref: + * @self: an #OstreeRepo + * @ref: a collection–ref to resolve + * @allow_noent: %TRUE to not throw an error if @ref doesn’t exist + * @flags: options controlling behaviour + * @out_rev: (out) (transfer full) (optional) (nullable): return location for + * the checksum corresponding to @ref, or %NULL if @allow_noent is %TRUE and + * the @ref could not be found + * @cancellable: (nullable): a #GCancellable, or %NULL + * @error: return location for a #GError, or %NULL + * + * Look up the checksum for the given collection–ref, returning it in @out_rev. + * This will search through the mirrors and remote refs. + * + * If @allow_noent is %TRUE and the given @ref cannot be found, %TRUE will be + * returned and @out_rev will be set to %NULL. If @allow_noent is %FALSE and + * the given @ref cannot be found, a %G_IO_ERROR_NOT_FOUND error will be + * returned. + * + * If you want to check only local refs, not remote or mirrored ones, use the + * flag %OSTREE_REPO_RESOLVE_REV_EXT_LOCAL_ONLY. This is analogous to using + * ostree_repo_resolve_rev_ext() but for collection-refs. + * + * Returns: %TRUE on success, %FALSE on failure + * Since: 2018.6 + */ +gboolean +ostree_repo_resolve_collection_ref (OstreeRepo *self, + const OstreeCollectionRef *ref, + gboolean allow_noent, + OstreeRepoResolveRevExtFlags flags, + char **out_rev, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *ret_contents = NULL; + + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (ref != NULL, FALSE); + g_return_val_if_fail (ref->collection_id != NULL && ref->ref_name != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* Check for the ref in the current transaction in case it hasn't been + * written to disk, to match the behavior of ostree_repo_resolve_rev() */ + if (self->in_transaction) + { + g_mutex_lock (&self->txn_lock); + if (self->txn.collection_refs) + { + const char *repo_collection_id = ostree_repo_get_collection_id (self); + /* If the collection ID doesn't match it's a remote ref */ + if (!(flags & OSTREE_REPO_RESOLVE_REV_EXT_LOCAL_ONLY) || + repo_collection_id == NULL || + g_strcmp0 (repo_collection_id, ref->collection_id) == 0) + { + ret_contents = g_strdup (g_hash_table_lookup (self->txn.collection_refs, ref)); + } + } + g_mutex_unlock (&self->txn_lock); + } + + /* Check for the ref on disk in the repo */ + if (ret_contents == NULL) + { + g_autoptr(GHashTable) refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + OstreeRepoListRefsExtFlags list_refs_flags; + + if (flags & OSTREE_REPO_RESOLVE_REV_EXT_LOCAL_ONLY) + list_refs_flags = OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES | OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_MIRRORS; + else + list_refs_flags = OSTREE_REPO_LIST_REFS_EXT_NONE; + + if (!ostree_repo_list_collection_refs (self, ref->collection_id, &refs, + list_refs_flags, cancellable, error)) + return FALSE; + + ret_contents = g_strdup (g_hash_table_lookup (refs, ref)); + } + + /* Check for the ref in the parent repo */ + if (ret_contents == NULL && self->parent_repo != NULL) + { + if (!ostree_repo_resolve_collection_ref (self->parent_repo, + ref, + TRUE, + flags, + &ret_contents, + cancellable, + error)) + return FALSE; + } + + if (ret_contents == NULL && !allow_noent) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Collection–ref (%s, %s) not found", + ref->collection_id, ref->ref_name); + return FALSE; + } + + if (out_rev != NULL) + *out_rev = g_steal_pointer (&ret_contents); + return TRUE; +} + +static gboolean +enumerate_refs_recurse (OstreeRepo *repo, + const char *remote, + OstreeRepoListRefsExtFlags flags, + const char *collection_id, + int base_dfd, + GString *base_path, + int child_dfd, + const char *path, + GHashTable *refs, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + const gboolean aliases_only = (flags & OSTREE_REPO_LIST_REFS_EXT_ALIASES) > 0; + + if (!glnx_dirfd_iterator_init_at (child_dfd, path, FALSE, &dfd_iter, error)) + return FALSE; + + while (TRUE) + { + guint len = base_path->len; + struct dirent *dent = NULL; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + /* https://github.com/ostreedev/ostree/issues/1285 + * Ignore any files that don't appear to be valid fragments; e.g. + * Red Hat has a tool that drops .rsync_info files into each + * directory it syncs. + **/ + if (!_ostree_validate_ref_fragment (dent->d_name, NULL)) + continue; + + g_string_append (base_path, dent->d_name); + + if (dent->d_type == DT_DIR) + { + g_string_append_c (base_path, '/'); + + if (!enumerate_refs_recurse (repo, remote, flags, collection_id, base_dfd, base_path, + dfd_iter.fd, dent->d_name, + refs, cancellable, error)) + return FALSE; + } + else + { + if (aliases_only && dent->d_type == DT_LNK) + { + g_autofree char *target = glnx_readlinkat_malloc (base_dfd, base_path->str, + cancellable, error); + const char *resolved_target = target; + if (!target) + return FALSE; + while (g_str_has_prefix (resolved_target, "../")) + resolved_target += 3; + g_hash_table_insert (refs, g_strdup (base_path->str), g_strdup (resolved_target)); + } + else if ((!aliases_only && dent->d_type == DT_REG) || dent->d_type == DT_LNK) + { + if (!add_ref_to_set (remote, collection_id, base_dfd, base_path->str, refs, + cancellable, error)) + return FALSE; + } + } + + g_string_truncate (base_path, len); + } + + return TRUE; +} + +static gboolean +_ostree_repo_list_refs_internal (OstreeRepo *self, + gboolean cut_prefix, + OstreeRepoListRefsExtFlags flags, + const char *refspec_prefix, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Listing refs", error); + + g_autofree char *remote = NULL; + g_autofree char *ref_prefix = NULL; + + g_autoptr(GHashTable) ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + if (refspec_prefix) + { + struct stat stbuf; + const char *prefix_path; + const char *path; + + /* special-case ":" and ":.", which ostree_parse_refspec won't like */ + if (g_str_has_suffix (refspec_prefix, ":") || + g_str_has_suffix (refspec_prefix, ":.")) + { + const char *colon = strrchr (refspec_prefix, ':'); + g_autofree char *r = g_strndup (refspec_prefix, colon - refspec_prefix); + if (ostree_validate_remote_name (r, NULL)) + { + remote = g_steal_pointer (&r); + ref_prefix = g_strdup ("."); + } + } + + if (!ref_prefix) + { + if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error)) + return FALSE; + } + + if (!(flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES) && remote) + { + prefix_path = glnx_strjoina ("refs/remotes/", remote, "/"); + path = glnx_strjoina (prefix_path, ref_prefix); + } + else + { + prefix_path = "refs/heads/"; + path = glnx_strjoina (prefix_path, ref_prefix); + } + + if (!glnx_fstatat_allow_noent (self->repo_dir_fd, path, &stbuf, 0, error)) + return FALSE; + if (errno == 0) + { + if (S_ISDIR (stbuf.st_mode)) + { + glnx_autofd int base_fd = -1; + g_autoptr(GString) base_path = g_string_new (""); + if (!cut_prefix) + g_string_printf (base_path, "%s/", ref_prefix); + + if (!glnx_opendirat (self->repo_dir_fd, cut_prefix ? path : prefix_path, TRUE, &base_fd, error)) + return FALSE; + + if (!enumerate_refs_recurse (self, remote, flags, NULL, base_fd, base_path, + base_fd, cut_prefix ? "." : ref_prefix, + ret_all_refs, cancellable, error)) + return FALSE; + } + else + { + glnx_autofd int prefix_dfd = -1; + + if (!glnx_opendirat (self->repo_dir_fd, prefix_path, TRUE, &prefix_dfd, error)) + return FALSE; + + if (!add_ref_to_set (remote, NULL, prefix_dfd, ref_prefix, ret_all_refs, + cancellable, error)) + return FALSE; + } + } + } + else + { + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + g_autoptr(GString) base_path = g_string_new (""); + glnx_autofd int refs_heads_dfd = -1; + + if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error)) + return FALSE; + + if (!enumerate_refs_recurse (self, NULL, flags, NULL, refs_heads_dfd, base_path, + refs_heads_dfd, ".", + ret_all_refs, cancellable, error)) + return FALSE; + + if (!(flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES)) + { + g_string_truncate (base_path, 0); + + if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent; + glnx_autofd int remote_dfd = -1; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (!dent) + break; + + if (dent->d_type != DT_DIR) + continue; + + if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error)) + return FALSE; + + if (!enumerate_refs_recurse (self, dent->d_name, flags, NULL, remote_dfd, base_path, + remote_dfd, ".", + ret_all_refs, + cancellable, error)) + return FALSE; + } + } + } + + ot_transfer_out_value (out_all_refs, &ret_all_refs); + return TRUE; +} + +/** + * ostree_repo_list_refs: + * @self: Repo + * @refspec_prefix: (allow-none): Only list refs which match this prefix + * @out_all_refs: (out) (element-type utf8 utf8) (transfer container): + * Mapping from refspec to checksum + * @cancellable: Cancellable + * @error: Error + * + * If @refspec_prefix is %NULL, list all local and remote refspecs, + * with their current values in @out_all_refs. Otherwise, only list + * refspecs which have @refspec_prefix as a prefix. + * + * @out_all_refs will be returned as a mapping from refspecs (including the + * remote name) to checksums. If @refspec_prefix is non-%NULL, it will be + * removed as a prefix from the hash table keys. + */ +gboolean +ostree_repo_list_refs (OstreeRepo *self, + const char *refspec_prefix, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error) +{ + return _ostree_repo_list_refs_internal (self, TRUE, + OSTREE_REPO_LIST_REFS_EXT_NONE, + refspec_prefix, out_all_refs, + cancellable, error); +} + +/** + * ostree_repo_list_refs_ext: + * @self: Repo + * @refspec_prefix: (allow-none): Only list refs which match this prefix + * @out_all_refs: (out) (element-type utf8 utf8) (transfer container): + * Mapping from refspec to checksum + * @flags: Options controlling listing behavior + * @cancellable: Cancellable + * @error: Error + * + * If @refspec_prefix is %NULL, list all local and remote refspecs, + * with their current values in @out_all_refs. Otherwise, only list + * refspecs which have @refspec_prefix as a prefix. + * + * @out_all_refs will be returned as a mapping from refspecs (including the + * remote name) to checksums. Differently from ostree_repo_list_refs(), the + * @refspec_prefix will not be removed from the refspecs in the hash table. + * + * Since: 2016.4 + */ +gboolean +ostree_repo_list_refs_ext (OstreeRepo *self, + const char *refspec_prefix, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error) +{ + return _ostree_repo_list_refs_internal (self, FALSE, flags, + refspec_prefix, out_all_refs, + cancellable, error); +} + +/** + * ostree_repo_remote_list_refs: + * @self: Repo + * @remote_name: Name of the remote. + * @out_all_refs: (out) (element-type utf8 utf8) (transfer container): + * Mapping from ref to checksum + * @cancellable: Cancellable + * @error: Error + * + */ +gboolean +ostree_repo_remote_list_refs (OstreeRepo *self, + const char *remote_name, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GBytes) summary_bytes = NULL; + g_autoptr(GHashTable) ret_all_refs = NULL; + + if (!ostree_repo_remote_fetch_summary (self, remote_name, + &summary_bytes, NULL, + cancellable, error)) + return FALSE; + + if (summary_bytes == NULL) + { + return glnx_throw (error, "Remote refs not available; server has no summary file"); + } + else + { + g_autoptr(GVariant) summary = NULL; + g_autoptr(GVariant) ref_map = NULL; + GVariantIter iter; + GVariant *child; + ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + summary = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE); + + ref_map = g_variant_get_child_value (summary, 0); + + g_variant_iter_init (&iter, ref_map); + while ((child = g_variant_iter_next_value (&iter)) != NULL) + { + const char *ref_name = NULL; + g_autoptr(GVariant) csum_v = NULL; + char tmp_checksum[OSTREE_SHA256_STRING_LEN+1]; + + g_variant_get_child (child, 0, "&s", &ref_name); + + if (ref_name != NULL) + { + g_variant_get_child (child, 1, "(t@aya{sv})", NULL, &csum_v, NULL); + + const guchar *csum_bytes = ostree_checksum_bytes_peek_validate (csum_v, error); + if (csum_bytes == NULL) + return FALSE; + + ostree_checksum_inplace_from_bytes (csum_bytes, tmp_checksum); + + g_hash_table_insert (ret_all_refs, + g_strdup (ref_name), + g_strdup (tmp_checksum)); + } + + g_variant_unref (child); + } + } + + ot_transfer_out_value (out_all_refs, &ret_all_refs); + return TRUE; +} + +static gboolean +remote_list_collection_refs_process_refs (OstreeRepo *self, + const gchar *remote_name, + const gchar *summary_collection_id, + GVariant *summary_refs, + GHashTable *ret_all_refs, + GError **error) +{ + gsize j, n; + + for (j = 0, n = g_variant_n_children (summary_refs); j < n; j++) + { + const guchar *csum_bytes; + g_autoptr(GVariant) ref_v = NULL, csum_v = NULL; + gchar tmp_checksum[OSTREE_SHA256_STRING_LEN + 1]; + const gchar *ref_name; + + /* Check the ref name. */ + ref_v = g_variant_get_child_value (summary_refs, j); + g_variant_get_child (ref_v, 0, "&s", &ref_name); + + if (!ostree_validate_rev (ref_name, error)) + return FALSE; + + /* Check the commit checksum. */ + g_variant_get_child (ref_v, 1, "(t@ay@a{sv})", NULL, &csum_v, NULL); + + csum_bytes = ostree_checksum_bytes_peek_validate (csum_v, error); + if (csum_bytes == NULL) + return FALSE; + + ostree_checksum_inplace_from_bytes (csum_bytes, tmp_checksum); + + g_hash_table_insert (ret_all_refs, + ostree_collection_ref_new (summary_collection_id, ref_name), + g_strdup (tmp_checksum)); + } + + return TRUE; +} + +/** + * ostree_repo_remote_list_collection_refs: + * @self: Repo + * @remote_name: Name of the remote. + * @out_all_refs: (out) (element-type OstreeCollectionRef utf8) (transfer container): + * Mapping from collection–ref to checksum + * @cancellable: Cancellable + * @error: Error + * + * List refs advertised by @remote_name, including refs which are part of + * collections. If the repository at @remote_name has a collection ID set, its + * refs will be returned with that collection ID; otherwise, they will be returned + * with a %NULL collection ID in each #OstreeCollectionRef key in @out_all_refs. + * Any refs for other collections stored in the repository will also be returned. + * No filtering is performed. + * + * Since: 2018.6 + */ +gboolean +ostree_repo_remote_list_collection_refs (OstreeRepo *self, + const char *remote_name, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GBytes) summary_bytes = NULL; + g_autoptr(GHashTable) ret_all_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + g_autoptr(GVariant) summary_v = NULL; + g_autoptr(GVariant) additional_metadata_v = NULL; + g_autoptr(GVariant) summary_refs = NULL; + const char *summary_collection_id; + g_autoptr(GVariantIter) summary_collection_map = NULL; + + if (!ostree_repo_remote_fetch_summary (self, remote_name, + &summary_bytes, NULL, + cancellable, error)) + return FALSE; + + if (summary_bytes == NULL) + return glnx_throw (error, "Remote refs not available; server has no summary file"); + + ret_all_refs = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + (GDestroyNotify) ostree_collection_ref_free, + g_free); + + summary_v = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE); + additional_metadata_v = g_variant_get_child_value (summary_v, 1); + + /* List the refs in the main map. */ + if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_ID, "&s", &summary_collection_id)) + summary_collection_id = NULL; + + summary_refs = g_variant_get_child_value (summary_v, 0); + + if (!remote_list_collection_refs_process_refs (self, remote_name, + summary_collection_id, summary_refs, + ret_all_refs, error)) + return FALSE; + + /* List the refs in the collection map. */ + if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_MAP, "a{sa(s(taya{sv}))}", &summary_collection_map)) + summary_collection_map = NULL; + + while (summary_collection_map != NULL && + g_variant_iter_loop (summary_collection_map, "{&s@a(s(taya{sv}))}", &summary_collection_id, &summary_refs)) + { + if (!remote_list_collection_refs_process_refs (self, remote_name, + summary_collection_id, summary_refs, + ret_all_refs, error)) + return FALSE; + } + + ot_transfer_out_value (out_all_refs, &ret_all_refs); + return TRUE; +} + +static char * +relative_symlink_to (const char *relpath, + const char *target) +{ + g_assert (*relpath); + g_assert (*target && *target != '/'); + + g_autoptr(GString) buf = g_string_new (""); + + while (TRUE) + { + const char *slash = strchr (relpath, '/'); + if (!slash) + break; + relpath = slash + 1; + g_string_append (buf, "../"); + } + + g_string_append (buf, target); + + return g_string_free (g_steal_pointer (&buf), FALSE); +} + +/* May specify @rev or @alias */ +gboolean +_ostree_repo_write_ref (OstreeRepo *self, + const char *remote, + const OstreeCollectionRef *ref, + const char *rev, + const char *alias, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int dfd = -1; + + g_return_val_if_fail (remote == NULL || ref->collection_id == NULL, FALSE); + g_return_val_if_fail (!(rev != NULL && alias != NULL), FALSE); + + if (remote != NULL && !ostree_validate_remote_name (remote, error)) + return FALSE; + if (ref->collection_id != NULL && !ostree_validate_collection_id (ref->collection_id, error)) + return FALSE; + if (!ostree_validate_rev (ref->ref_name, error)) + return FALSE; + + if (remote == NULL && + (ref->collection_id == NULL || g_strcmp0 (ref->collection_id, ostree_repo_get_collection_id (self)) == 0)) + { + if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, + &dfd, error)) + return FALSE; + } + else if (remote == NULL && ref->collection_id != NULL) + { + glnx_autofd int refs_mirrors_dfd = -1; + + /* refs/mirrors might not exist in older repositories, so create it. */ + if (!glnx_shutil_mkdir_p_at_open (self->repo_dir_fd, "refs/mirrors", 0777, + &refs_mirrors_dfd, cancellable, error)) + return FALSE; + + if (rev != NULL) + { + /* Ensure we have a dir for the collection */ + if (!glnx_shutil_mkdir_p_at (refs_mirrors_dfd, ref->collection_id, 0777, cancellable, error)) + return FALSE; + } + + dfd = glnx_opendirat_with_errno (refs_mirrors_dfd, ref->collection_id, TRUE); + if (dfd < 0 && (errno != ENOENT || rev != NULL)) + return glnx_throw_errno_prefix (error, "Opening mirrors/ dir %s", ref->collection_id); + } + else + { + glnx_autofd int refs_remotes_dfd = -1; + + if (!glnx_opendirat (self->repo_dir_fd, "refs/remotes", TRUE, + &refs_remotes_dfd, error)) + return FALSE; + + if (rev != NULL) + { + /* Ensure we have a dir for the remote */ + if (!glnx_shutil_mkdir_p_at (refs_remotes_dfd, remote, 0777, cancellable, error)) + return FALSE; + } + + dfd = glnx_opendirat_with_errno (refs_remotes_dfd, remote, TRUE); + if (dfd < 0 && (errno != ENOENT || rev != NULL)) + return glnx_throw_errno_prefix (error, "Opening remotes/ dir %s", remote); + } + + if (rev == NULL && alias == NULL) + { + if (dfd >= 0) + { + if (!ot_ensure_unlinked_at (dfd, ref->ref_name, error)) + return FALSE; + } + } + else if (rev != NULL) + { + if (!write_checksum_file_at (self, dfd, ref->ref_name, rev, cancellable, error)) + return FALSE; + } + else if (alias != NULL) + { + const char *lastslash = strrchr (ref->ref_name, '/'); + + if (lastslash) + { + char *parent = strdupa (ref->ref_name); + parent[lastslash - ref->ref_name] = '\0'; + + if (!glnx_shutil_mkdir_p_at (dfd, parent, DEFAULT_DIRECTORY_MODE, cancellable, error)) + return FALSE; + } + + g_autofree char *reltarget = relative_symlink_to (ref->ref_name, alias); + g_autofree char *tmplink = NULL; + if (!_ostree_make_temporary_symlink_at (self->tmp_dir_fd, reltarget, + &tmplink, cancellable, error)) + return FALSE; + if (!glnx_renameat (self->tmp_dir_fd, tmplink, dfd, ref->ref_name, error)) + return FALSE; + } + + if (!_ostree_repo_update_mtime (self, error)) + return FALSE; + + /* Update the summary after updating the mtime so the summary doesn't look + * out of date */ + if (!self->in_transaction && !_ostree_repo_maybe_regenerate_summary (self, cancellable, error)) + return FALSE; + + return TRUE; +} + +gboolean +_ostree_repo_update_refs (OstreeRepo *self, + GHashTable *refs, /* (element-type utf8 utf8) */ + GCancellable *cancellable, + GError **error) +{ + GLNX_HASH_TABLE_FOREACH_KV (refs, const char*, refspec, const char*, rev) + { + g_autofree char *remote = NULL; + g_autofree char *ref_name = NULL; + if (!ostree_parse_refspec (refspec, &remote, &ref_name, error)) + return FALSE; + + const OstreeCollectionRef ref = { NULL, ref_name }; + if (!_ostree_repo_write_ref (self, remote, &ref, rev, NULL, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +gboolean +_ostree_repo_update_collection_refs (OstreeRepo *self, + GHashTable *refs, /* (element-type OstreeCollectionRef utf8) */ + GCancellable *cancellable, + GError **error) +{ + GHashTableIter hash_iter; + gpointer key, value; + + g_hash_table_iter_init (&hash_iter, refs); + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + const OstreeCollectionRef *ref = key; + const char *rev = value; + + if (!_ostree_repo_write_ref (self, NULL, ref, rev, NULL, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_repo_list_collection_refs: + * @self: Repo + * @match_collection_id: (nullable): If non-%NULL, only list refs from this collection + * @out_all_refs: (out) (element-type OstreeCollectionRef utf8) (transfer container): + * Mapping from collection–ref to checksum + * @flags: Options controlling listing behavior + * @cancellable: Cancellable + * @error: Error + * + * List all local, mirrored, and remote refs, mapping them to the commit + * checksums they currently point to in @out_all_refs. If @match_collection_id + * is specified, the results will be limited to those with an equal collection + * ID. + * + * #OstreeCollectionRefs are guaranteed to be returned with their collection ID + * set to a non-%NULL value; so no refs from `refs/heads` will be listed if no + * collection ID is configured for the repository + * (ostree_repo_get_collection_id()). + * + * If you want to exclude refs from `refs/remotes`, use + * %OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES in @flags. Similarly use + * %OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_MIRRORS to exclude refs from + * `refs/mirrors`. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: 2018.6 + */ +gboolean +ostree_repo_list_collection_refs (OstreeRepo *self, + const char *match_collection_id, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Listing refs", error); + + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (match_collection_id != NULL && !ostree_validate_collection_id (match_collection_id, error)) + return FALSE; + + g_autoptr(GPtrArray) refs_dirs = g_ptr_array_new (); + if (!(flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_MIRRORS)) + g_ptr_array_add (refs_dirs, "refs/mirrors"); + if (!(flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES)) + g_ptr_array_add (refs_dirs, "refs/remotes"); + g_ptr_array_add (refs_dirs, NULL); + + g_autoptr(GHashTable) ret_all_refs = NULL; + + ret_all_refs = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + (GDestroyNotify) ostree_collection_ref_free, + g_free); + + g_autoptr(GString) base_path = g_string_new (""); + + const gchar *main_collection_id = ostree_repo_get_collection_id (self); + + if (main_collection_id != NULL && + (match_collection_id == NULL || g_strcmp0 (match_collection_id, main_collection_id) == 0)) + { + glnx_autofd int refs_heads_dfd = -1; + + if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error)) + return FALSE; + + if (!enumerate_refs_recurse (self, NULL, flags, + main_collection_id, refs_heads_dfd, base_path, + refs_heads_dfd, ".", + ret_all_refs, cancellable, error)) + return FALSE; + } + + g_string_truncate (base_path, 0); + + for (const char **iter = (const char **)refs_dirs->pdata; iter && *iter; iter++) + { + const char *refs_dir = *iter; + gboolean refs_dir_exists = FALSE; + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + + if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, refs_dir, + &dfd_iter, &refs_dir_exists, error)) + return FALSE; + + while (refs_dir_exists) + { + struct dirent *dent; + glnx_autofd int subdir_fd = -1; + const gchar *current_collection_id; + g_autofree gchar *remote_collection_id = NULL; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (!dent) + break; + + if (dent->d_type != DT_DIR) + continue; + + if (g_strcmp0 (refs_dir, "refs/mirrors") == 0) + { + if (match_collection_id != NULL && g_strcmp0 (match_collection_id, dent->d_name) != 0) + continue; + else + current_collection_id = dent->d_name; + } + else /* refs_dir = "refs/remotes" */ + { + g_autoptr(GError) local_error = NULL; + if (!ostree_repo_get_remote_option (self, dent->d_name, "collection-id", + NULL, &remote_collection_id, &local_error) || + !ostree_validate_collection_id (remote_collection_id, &local_error)) + { + g_debug ("Ignoring remote ‘%s’ due to no valid collection ID being configured for it: %s", + dent->d_name, local_error->message); + g_clear_error (&local_error); + continue; + } + + if (match_collection_id != NULL && g_strcmp0 (match_collection_id, remote_collection_id) != 0) + continue; + else + current_collection_id = remote_collection_id; + } + + if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &subdir_fd, error)) + return FALSE; + + if (!enumerate_refs_recurse (self, NULL, flags, + current_collection_id, subdir_fd, base_path, + subdir_fd, ".", + ret_all_refs, + cancellable, error)) + return FALSE; + } + } + + ot_transfer_out_value (out_all_refs, &ret_all_refs); + return TRUE; +} diff --git a/src/libostree/ostree-repo-static-delta-compilation-analysis.c b/src/libostree/ostree-repo-static-delta-compilation-analysis.c new file mode 100644 index 0000000..53486c2 --- /dev/null +++ b/src/libostree/ostree-repo-static-delta-compilation-analysis.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2015 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include "ostree-core-private.h" +#include "ostree-repo-private.h" +#include "ostree-lzma-compressor.h" +#include "ostree-repo-static-delta-private.h" +#include "ostree-diff.h" +#include "ostree-rollsum.h" +#include "otutil.h" +#include "ostree-varint.h" + +void +_ostree_delta_content_sizenames_free (gpointer v) +{ + OstreeDeltaContentSizeNames *ce = v; + g_free (ce->checksum); + g_ptr_array_unref (ce->basenames); + g_free (ce); +} + +static gboolean +build_content_sizenames_recurse (OstreeRepo *repo, + OstreeRepoCommitTraverseIter *iter, + GHashTable *sizenames_map, + GHashTable *include_only_objects, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + + while (TRUE) + { + OstreeRepoCommitIterResult iterres = + ostree_repo_commit_traverse_iter_next (iter, cancellable, error); + + if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_ERROR) + goto out; + else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_END) + break; + else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_FILE) + { + char *name; + char *checksum; + OstreeDeltaContentSizeNames *csizenames; + + ostree_repo_commit_traverse_iter_get_file (iter, &name, &checksum); + + if (include_only_objects && !g_hash_table_contains (include_only_objects, checksum)) + continue; + + csizenames = g_hash_table_lookup (sizenames_map, checksum); + if (!csizenames) + { + g_autoptr(GFileInfo) finfo = NULL; + + if (!ostree_repo_load_file (repo, checksum, + NULL, &finfo, NULL, + cancellable, error)) + goto out; + + if (g_file_info_get_file_type (finfo) != G_FILE_TYPE_REGULAR) + continue; + + csizenames = g_new0 (OstreeDeltaContentSizeNames, 1); + csizenames->checksum = g_strdup (checksum); + csizenames->size = g_file_info_get_size (finfo); + g_hash_table_replace (sizenames_map, csizenames->checksum, csizenames); + } + + if (!csizenames->basenames) + csizenames->basenames = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (csizenames->basenames, g_strdup (name)); + } + else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_DIR) + { + char *name; + char *content_checksum; + char *meta_checksum; + g_autoptr(GVariant) dirtree = NULL; + ostree_cleanup_repo_commit_traverse_iter + OstreeRepoCommitTraverseIter subiter = { 0, }; + + ostree_repo_commit_traverse_iter_get_dir (iter, &name, &content_checksum, &meta_checksum); + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_DIR_TREE, + content_checksum, &dirtree, + error)) + goto out; + + if (!ostree_repo_commit_traverse_iter_init_dirtree (&subiter, repo, dirtree, + OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE, + error)) + goto out; + + if (!build_content_sizenames_recurse (repo, &subiter, + sizenames_map, include_only_objects, + cancellable, error)) + goto out; + } + else + g_assert_not_reached (); + } + ret = TRUE; + out: + return ret; +} + +static int +compare_sizenames (const void *a, + const void *b) +{ + OstreeDeltaContentSizeNames *sn_a = *(OstreeDeltaContentSizeNames**)(void*)a; + OstreeDeltaContentSizeNames *sn_b = *(OstreeDeltaContentSizeNames**)(void*)b; + + return sn_a->size - sn_b->size; +} + +/* + * Generate a sorted array of [(checksum: str, size: uint64, names: array[string]), ...] + * for regular file content. + */ +static gboolean +build_content_sizenames_filtered (OstreeRepo *repo, + GVariant *commit, + GHashTable *include_only_objects, + GPtrArray **out_sizenames, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GPtrArray) ret_sizenames = + g_ptr_array_new_with_free_func (_ostree_delta_content_sizenames_free); + g_autoptr(GHashTable) sizenames_map = + g_hash_table_new_full (g_str_hash, g_str_equal, NULL, _ostree_delta_content_sizenames_free); + ostree_cleanup_repo_commit_traverse_iter + OstreeRepoCommitTraverseIter iter = { 0, }; + + if (!ostree_repo_commit_traverse_iter_init_commit (&iter, repo, commit, + OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE, + error)) + goto out; + + if (!build_content_sizenames_recurse (repo, &iter, sizenames_map, include_only_objects, + cancellable, error)) + goto out; + + { GHashTableIter hashiter; + gpointer hkey, hvalue; + + g_hash_table_iter_init (&hashiter, sizenames_map); + while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue)) + { + g_hash_table_iter_steal (&hashiter); + g_ptr_array_add (ret_sizenames, hvalue); + } + } + + g_ptr_array_sort (ret_sizenames, compare_sizenames); + + ret = TRUE; + if (out_sizenames) + *out_sizenames = g_steal_pointer (&ret_sizenames); + out: + return ret; +} + +static gboolean +string_array_nonempty_intersection (GPtrArray *a, + GPtrArray *b, + gboolean fuzzy) +{ + guint i; + for (i = 0; i < a->len; i++) + { + guint j; + const char *a_str = a->pdata[i]; + const char *a_dot = strchr (a_str, '.'); + for (j = 0; j < b->len; j++) + { + const char *b_str = b->pdata[j]; + const char *b_dot = strchr (b_str, '.'); + /* When doing fuzzy comparison, just compare the part before the '.' if it exists. */ + if (fuzzy && a_dot && b_dot && b_dot - b_str && b_dot - b_str == a_dot - a_str) + { + if (strncmp (a_str, b_str, a_dot - a_str) == 0) + return TRUE; + } + else + { + if (strcmp (a_str, b_str) == 0) + return TRUE; + } + } + } + return FALSE; +} + +static gboolean +sizename_is_delta_candidate (OstreeDeltaContentSizeNames *sizename) +{ + /* Don't build candidates for the empty object */ + if (sizename->size == 0) + return FALSE; + + /* Look for known non-delta-able files (currently just compression like xz) */ + for (guint i = 0; i < sizename->basenames->len; i++) + { + const char *name = sizename->basenames->pdata[i]; + /* We could replace this down the line with g_content_type_guess() or so, + * but it's not clear to me that's a major win; we'd still need to + * maintain a list of compression formats, and this doesn't require + * allocation. + * NB: We explicitly don't have .gz here in case someone might be + * using --rsyncable for that. + */ + const char *dot = strrchr (name, '.'); + if (!dot) + continue; + const char *extension = dot+1; + /* Don't add .gz here, see above */ + if (g_str_equal (extension, "xz") || g_str_equal (extension, "bz2")) + return FALSE; + } + + /* Let's try it */ + return TRUE; +} + +/* + * Build up a map of files with matching basenames and similar size, + * and use it to find apparently similar objects. + * + * @new_reachable_regfile_content is a Set of new regular + * file objects. + * + * Currently, @out_modified_regfile_content will be a Map; + * however in the future it would be easy to have this function return + * multiple candidate matches. The hard part would be changing + * the delta compiler to iterate over all matches, determine + * a cost for each one, then pick the best. + */ +gboolean +_ostree_delta_compute_similar_objects (OstreeRepo *repo, + GVariant *from_commit, + GVariant *to_commit, + GHashTable *new_reachable_regfile_content, + guint similarity_percent_threshold, + GHashTable **out_modified_regfile_content, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GHashTable) ret_modified_regfile_content = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + g_autoptr(GPtrArray) from_sizes = NULL; + g_autoptr(GPtrArray) to_sizes = NULL; + guint i, j; + guint lower; + guint upper; + + if (!build_content_sizenames_filtered (repo, from_commit, NULL, + &from_sizes, + cancellable, error)) + goto out; + + if (!build_content_sizenames_filtered (repo, to_commit, new_reachable_regfile_content, + &to_sizes, + cancellable, error)) + goto out; + + /* Iterate over all newly added objects, find objects which have + * similar basename and sizes. + * + * Because the arrays are sorted by size, we can maintain a `lower` + * bound on the original (from) objects to start searching. + */ + lower = 0; + upper = from_sizes->len; + for (i = 0; i < to_sizes->len; i++) + { + int fuzzy; + gboolean found = FALSE; + OstreeDeltaContentSizeNames *to_sizenames = to_sizes->pdata[i]; + const guint64 min_threshold = to_sizenames->size * + (1.0-similarity_percent_threshold/100.0); + const guint64 max_threshold = to_sizenames->size * + (1.0+similarity_percent_threshold/100.0); + + if (!sizename_is_delta_candidate (to_sizenames)) + continue; + + for (fuzzy = 0; fuzzy < 2 && !found; fuzzy++) + { + for (j = lower; j < upper; j++) + { + OstreeDeltaContentSizeNames *from_sizenames = from_sizes->pdata[j]; + if (!sizename_is_delta_candidate (from_sizenames)) + continue; + + if (from_sizenames->size < min_threshold) + { + lower++; + continue; + } + + if (from_sizenames->size > max_threshold) + break; + + if (!string_array_nonempty_intersection (from_sizenames->basenames, + to_sizenames->basenames, + fuzzy == 1)) + { + continue; + } + + /* Only one candidate right now */ + g_hash_table_insert (ret_modified_regfile_content, + g_strdup (to_sizenames->checksum), + g_strdup (from_sizenames->checksum)); + found = TRUE; + break; + } + } + } + + ret = TRUE; + if (out_modified_regfile_content) + *out_modified_regfile_content = g_steal_pointer (&ret_modified_regfile_content); + out: + return ret; +} diff --git a/src/libostree/ostree-repo-static-delta-compilation.c b/src/libostree/ostree-repo-static-delta-compilation.c new file mode 100644 index 0000000..3e9a8e3 --- /dev/null +++ b/src/libostree/ostree-repo-static-delta-compilation.c @@ -0,0 +1,1597 @@ +/* + * Copyright (C) 2013,2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "ostree-core-private.h" +#include "ostree-repo-private.h" +#include "ostree-lzma-compressor.h" +#include "ostree-repo-static-delta-private.h" +#include "ostree-diff.h" +#include "ostree-rollsum.h" +#include "otutil.h" +#include "libglnx.h" +#include "ostree-varint.h" +#include "bsdiff/bsdiff.h" + +#define CONTENT_SIZE_SIMILARITY_THRESHOLD_PERCENT (30) + +typedef enum { + DELTAOPT_FLAG_NONE = (1 << 0), + DELTAOPT_FLAG_DISABLE_BSDIFF = (1 << 1), + DELTAOPT_FLAG_VERBOSE = (1 << 2) +} DeltaOpts; + +typedef struct { + guint64 compressed_size; + guint64 uncompressed_size; + GPtrArray *objects; + GString *payload; + GString *operations; + GHashTable *mode_set; /* GVariant(uuu) -> offset */ + GPtrArray *modes; + GHashTable *xattr_set; /* GVariant(ayay) -> offset */ + GPtrArray *xattrs; + GLnxTmpfile part_tmpf; + GVariant *header; +} OstreeStaticDeltaPartBuilder; + +typedef struct { + GPtrArray *parts; + GPtrArray *fallback_objects; + guint64 loose_compressed_size; + guint64 min_fallback_size_bytes; + guint64 max_bsdiff_size_bytes; + guint64 max_chunk_size_bytes; + guint64 rollsum_size; + guint n_rollsum; + guint n_bsdiff; + guint n_fallback; + gboolean swap_endian; + int parts_dfd; + DeltaOpts delta_opts; +} OstreeStaticDeltaBuilder; + +/* Get an input stream for a GVariant */ +static GInputStream * +variant_to_inputstream (GVariant *variant) +{ + GMemoryInputStream *ret = (GMemoryInputStream*) + g_memory_input_stream_new_from_data (g_variant_get_data (variant), + g_variant_get_size (variant), + NULL); + g_object_set_data_full ((GObject*)ret, "ot-variant-data", + g_variant_ref (variant), (GDestroyNotify) g_variant_unref); + return (GInputStream*)ret; +} + +static GBytes * +objtype_checksum_array_new (GPtrArray *objects) +{ + guint i; + GByteArray *ret = g_byte_array_new (); + + for (i = 0; i < objects->len; i++) + { + GVariant *serialized_key = objects->pdata[i]; + OstreeObjectType objtype; + const char *checksum; + guint8 csum[OSTREE_SHA256_DIGEST_LEN]; + guint8 objtype_v; + + ostree_object_name_deserialize (serialized_key, &checksum, &objtype); + objtype_v = (guint8) objtype; + + ostree_checksum_inplace_to_bytes (checksum, csum); + + g_byte_array_append (ret, &objtype_v, 1); + g_byte_array_append (ret, csum, sizeof (csum)); + } + return g_byte_array_free_to_bytes (ret); +} + +static void +ostree_static_delta_part_builder_unref (OstreeStaticDeltaPartBuilder *part_builder) +{ + if (part_builder->objects) + g_ptr_array_unref (part_builder->objects); + if (part_builder->payload) + g_string_free (part_builder->payload, TRUE); + if (part_builder->operations) + g_string_free (part_builder->operations, TRUE); + g_hash_table_unref (part_builder->mode_set); + g_ptr_array_unref (part_builder->modes); + g_hash_table_unref (part_builder->xattr_set); + g_ptr_array_unref (part_builder->xattrs); + glnx_tmpfile_clear (&part_builder->part_tmpf); + if (part_builder->header) + g_variant_unref (part_builder->header); + g_free (part_builder); +} + +static guint +mode_chunk_hash (const void *vp) +{ + GVariant *v = (GVariant*)vp; + guint uid, gid, mode; + g_variant_get (v, "(uuu)", &uid, &gid, &mode); + return uid + gid + mode; +} + +static gboolean +mode_chunk_equals (const void *one, const void *two) +{ + GVariant *v1 = (GVariant*)one; + GVariant *v2 = (GVariant*)two; + guint uid1, gid1, mode1; + guint uid2, gid2, mode2; + + g_variant_get (v1, "(uuu)", &uid1, &gid1, &mode1); + g_variant_get (v2, "(uuu)", &uid2, &gid2, &mode2); + + return uid1 == uid2 && gid1 == gid2 && mode1 == mode2; +} + +static guint +bufhash (const void *b, gsize len) +{ + const signed char *p, *e; + guint32 h = 5381; + + for (p = (signed char *)b, e = (signed char *)b + len; p != e; p++) + h = (h << 5) + h + *p; + + return h; +} + +static guint +xattr_chunk_hash (const void *vp) +{ + GVariant *v = (GVariant*)vp; + gsize n = g_variant_n_children (v); + guint i; + guint32 h = 5381; + + for (i = 0; i < n; i++) + { + const guint8* name; + const guint8* value_data; + g_autoptr(GVariant) value = NULL; + gsize value_len; + + g_variant_get_child (v, i, "(^&ay@ay)", + &name, &value); + value_data = g_variant_get_fixed_array (value, &value_len, 1); + + h += g_str_hash (name); + h += bufhash (value_data, value_len); + } + + return h; +} + +static gboolean +xattr_chunk_equals (const void *one, const void *two) +{ + GVariant *v1 = (GVariant*)one; + GVariant *v2 = (GVariant*)two; + gsize l1 = g_variant_get_size (v1); + gsize l2 = g_variant_get_size (v2); + + if (l1 != l2) + return FALSE; + + if (l1 == 0) + return l2 == 0; + + return memcmp (g_variant_get_data (v1), g_variant_get_data (v2), l1) == 0; +} + +static gboolean +finish_part (OstreeStaticDeltaBuilder *builder, GError **error) +{ + OstreeStaticDeltaPartBuilder *part_builder = builder->parts->pdata[builder->parts->len - 1]; + g_autofree guchar *part_checksum = NULL; + g_autoptr(GBytes) objtype_checksum_array = NULL; + g_autoptr(GBytes) checksum_bytes = NULL; + g_autoptr(GOutputStream) part_temp_outstream = NULL; + g_autoptr(GInputStream) part_in = NULL; + g_autoptr(GInputStream) part_payload_in = NULL; + g_autoptr(GMemoryOutputStream) part_payload_out = NULL; + g_autoptr(GConverterOutputStream) part_payload_compressor = NULL; + g_autoptr(GConverter) compressor = NULL; + g_autoptr(GVariant) delta_part_content = NULL; + g_autoptr(GVariant) delta_part = NULL; + g_autoptr(GVariant) delta_part_header = NULL; + g_auto(GVariantBuilder) mode_builder = OT_VARIANT_BUILDER_INITIALIZER; + g_auto(GVariantBuilder) xattr_builder = OT_VARIANT_BUILDER_INITIALIZER; + guint8 compression_type_char; + + g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uuu)")); + g_variant_builder_init (&xattr_builder, G_VARIANT_TYPE ("aa(ayay)")); + guint j; + + for (j = 0; j < part_builder->modes->len; j++) + g_variant_builder_add_value (&mode_builder, part_builder->modes->pdata[j]); + + for (j = 0; j < part_builder->xattrs->len; j++) + g_variant_builder_add_value (&xattr_builder, part_builder->xattrs->pdata[j]); + + { + g_autoptr(GBytes) payload_b = g_string_free_to_bytes (g_steal_pointer (&part_builder->payload)); + g_autoptr(GBytes) operations_b = g_string_free_to_bytes (g_steal_pointer (&part_builder->operations)); + + delta_part_content = g_variant_new ("(a(uuu)aa(ayay)@ay@ay)", + &mode_builder, &xattr_builder, + ot_gvariant_new_ay_bytes (payload_b), + ot_gvariant_new_ay_bytes (operations_b)); + g_variant_ref_sink (delta_part_content); + } + + /* Hardcode xz for now */ + compressor = (GConverter*)_ostree_lzma_compressor_new (NULL); + compression_type_char = 'x'; + part_payload_in = variant_to_inputstream (delta_part_content); + part_payload_out = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free); + part_payload_compressor = (GConverterOutputStream*)g_converter_output_stream_new ((GOutputStream*)part_payload_out, compressor); + + { + gssize n_bytes_written = g_output_stream_splice ((GOutputStream*)part_payload_compressor, part_payload_in, + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE, + NULL, error); + if (n_bytes_written < 0) + return FALSE; + } + + g_clear_pointer (&delta_part_content, g_variant_unref); + + { g_autoptr(GBytes) payload = g_memory_output_stream_steal_as_bytes (part_payload_out); + delta_part = g_variant_ref_sink (g_variant_new ("(y@ay)", + compression_type_char, + ot_gvariant_new_ay_bytes (payload))); + } + + if (!glnx_open_tmpfile_linkable_at (builder->parts_dfd, ".", O_RDWR | O_CLOEXEC, + &part_builder->part_tmpf, error)) + return FALSE; + + part_temp_outstream = g_unix_output_stream_new (part_builder->part_tmpf.fd, FALSE); + + part_in = variant_to_inputstream (delta_part); + if (!ot_gio_splice_get_checksum (part_temp_outstream, part_in, + &part_checksum, + NULL, error)) + return FALSE; + + checksum_bytes = g_bytes_new (part_checksum, OSTREE_SHA256_DIGEST_LEN); + objtype_checksum_array = objtype_checksum_array_new (part_builder->objects); + delta_part_header = g_variant_new ("(u@aytt@ay)", + maybe_swap_endian_u32 (builder->swap_endian, OSTREE_DELTAPART_VERSION), + ot_gvariant_new_ay_bytes (checksum_bytes), + maybe_swap_endian_u64 (builder->swap_endian, (guint64) g_variant_get_size (delta_part)), + maybe_swap_endian_u64 (builder->swap_endian, part_builder->uncompressed_size), + ot_gvariant_new_ay_bytes (objtype_checksum_array)); + g_variant_ref_sink (delta_part_header); + + part_builder->header = g_variant_ref (delta_part_header); + part_builder->compressed_size = g_variant_get_size (delta_part); + + if (builder->delta_opts & DELTAOPT_FLAG_VERBOSE) + { + g_printerr ("part %u n:%u compressed:%" G_GUINT64_FORMAT " uncompressed:%" G_GUINT64_FORMAT "\n", + builder->parts->len, part_builder->objects->len, + part_builder->compressed_size, + part_builder->uncompressed_size); + } + + return TRUE; +} + +static OstreeStaticDeltaPartBuilder * +allocate_part (OstreeStaticDeltaBuilder *builder, GError **error) +{ + if (builder->parts->len > 0) + { + if (!finish_part (builder, error)) + return NULL; + } + + OstreeStaticDeltaPartBuilder *part = g_new0 (OstreeStaticDeltaPartBuilder, 1); + part->objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); + part->payload = g_string_new (NULL); + part->operations = g_string_new (NULL); + part->uncompressed_size = 0; + part->mode_set = g_hash_table_new_full (mode_chunk_hash, mode_chunk_equals, + (GDestroyNotify)g_variant_unref, NULL); + part->modes = g_ptr_array_new (); + part->xattr_set = g_hash_table_new_full (xattr_chunk_hash, xattr_chunk_equals, + (GDestroyNotify)g_variant_unref, NULL); + part->xattrs = g_ptr_array_new (); + g_ptr_array_add (builder->parts, part); + return part; +} + +static gsize +allocate_part_buffer_space (OstreeStaticDeltaPartBuilder *current_part, + guint len) +{ + gsize empty_space; + gsize old_len; + + old_len = current_part->payload->len; + empty_space = current_part->payload->allocated_len - current_part->payload->len; + + if (empty_space < len) + { + gsize origlen; + origlen = current_part->payload->len; + g_string_set_size (current_part->payload, current_part->payload->allocated_len + (len - empty_space)); + current_part->payload->len = origlen; + } + + return old_len; +} + +static gsize +write_unique_variant_chunk (OstreeStaticDeltaPartBuilder *current_part, + GHashTable *hash, + GPtrArray *ordered, + GVariant *key) +{ + gpointer target_offsetp; + gsize offset; + + if (g_hash_table_lookup_extended (hash, key, NULL, &target_offsetp)) + return GPOINTER_TO_UINT (target_offsetp); + + offset = ordered->len; + target_offsetp = GUINT_TO_POINTER (offset); + g_hash_table_insert (hash, g_variant_ref (key), target_offsetp); + g_ptr_array_add (ordered, key); + + return offset; +} + +static gboolean +splice_stream_to_payload (OstreeStaticDeltaPartBuilder *current_part, + GInputStream *istream, + GCancellable *cancellable, + GError **error) +{ + while (TRUE) + { + const guint readlen = 4096; + allocate_part_buffer_space (current_part, readlen); + + gsize bytes_read; + if (!g_input_stream_read_all (istream, + current_part->payload->str + current_part->payload->len, + readlen, + &bytes_read, + cancellable, error)) + return FALSE; + if (bytes_read == 0) + break; + + current_part->payload->len += bytes_read; + } + + return TRUE; +} + +static void +write_content_mode_xattrs (OstreeRepo *repo, + OstreeStaticDeltaPartBuilder *current_part, + GFileInfo *content_finfo, + GVariant *content_xattrs, + gsize *out_mode_offset, + gsize *out_xattr_offset) +{ + guint32 uid = + g_file_info_get_attribute_uint32 (content_finfo, "unix::uid"); + guint32 gid = + g_file_info_get_attribute_uint32 (content_finfo, "unix::gid"); + guint32 mode = + g_file_info_get_attribute_uint32 (content_finfo, "unix::mode"); + g_autoptr(GVariant) modev + = g_variant_ref_sink (g_variant_new ("(uuu)", + GUINT32_TO_BE (uid), + GUINT32_TO_BE (gid), + GUINT32_TO_BE (mode))); + + *out_mode_offset = write_unique_variant_chunk (current_part, + current_part->mode_set, + current_part->modes, + modev); + *out_xattr_offset = write_unique_variant_chunk (current_part, + current_part->xattr_set, + current_part->xattrs, + content_xattrs); +} + +static gboolean +process_one_object (OstreeRepo *repo, + OstreeStaticDeltaBuilder *builder, + OstreeStaticDeltaPartBuilder **current_part_val, + const char *checksum, + OstreeObjectType objtype, + GCancellable *cancellable, + GError **error) +{ + OstreeStaticDeltaPartBuilder *current_part = *current_part_val; + g_autoptr(GFileInfo) content_finfo = NULL; + g_autoptr(GVariant) content_xattrs = NULL; + guint64 content_size; + g_autoptr(GInputStream) content_stream = NULL; + + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + { + if (!ostree_repo_load_object_stream (repo, objtype, checksum, + &content_stream, &content_size, + cancellable, error)) + return FALSE; + } + else + { + if (!ostree_repo_load_file (repo, checksum, &content_stream, + &content_finfo, &content_xattrs, + cancellable, error)) + return FALSE; + content_size = g_file_info_get_size (content_finfo); + } + + /* Check to see if this delta is maximum size */ + if (current_part->objects->len > 0 && + current_part->payload->len + content_size > builder->max_chunk_size_bytes) + { + current_part = allocate_part (builder, error); + if (current_part == NULL) + return FALSE; + *current_part_val = current_part; + } + + guint64 compressed_size; + if (!ostree_repo_query_object_storage_size (repo, objtype, checksum, + &compressed_size, + cancellable, error)) + return FALSE; + builder->loose_compressed_size += compressed_size; + + current_part->uncompressed_size += content_size; + + g_ptr_array_add (current_part->objects, ostree_object_name_serialize (checksum, objtype)); + + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + { + gsize object_payload_start; + + object_payload_start = current_part->payload->len; + + if (!splice_stream_to_payload (current_part, content_stream, + cancellable, error)) + return FALSE; + + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE); + _ostree_write_varuint64 (current_part->operations, content_size); + _ostree_write_varuint64 (current_part->operations, object_payload_start); + } + else + { + gsize mode_offset, xattr_offset, content_offset; + guint32 mode = g_file_info_get_attribute_uint32 (content_finfo, "unix::mode"); + + write_content_mode_xattrs (repo, current_part, content_finfo, content_xattrs, + &mode_offset, &xattr_offset); + + if (S_ISLNK (mode)) + { + g_assert (content_stream == NULL); + const char *target = g_file_info_get_symlink_target (content_finfo); + content_stream = + g_memory_input_stream_new_from_data (target, strlen (target), NULL); + content_size = strlen (target); + } + else + { + g_assert (S_ISREG (mode)); + } + + content_offset = current_part->payload->len; + if (!splice_stream_to_payload (current_part, content_stream, + cancellable, error)) + return FALSE; + + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE); + _ostree_write_varuint64 (current_part->operations, mode_offset); + _ostree_write_varuint64 (current_part->operations, xattr_offset); + _ostree_write_varuint64 (current_part->operations, content_size); + _ostree_write_varuint64 (current_part->operations, content_offset); + } + + return TRUE; +} + +typedef struct { + char *from_checksum; +} ContentBsdiff; + +typedef struct { + char *from_checksum; + OstreeRollsumMatches *matches; +} ContentRollsum; + +static void +content_rollsums_free (ContentRollsum *rollsum) +{ + g_free (rollsum->from_checksum); + _ostree_rollsum_matches_free (rollsum->matches); + g_free (rollsum); +} + +static void +content_bsdiffs_free (ContentBsdiff *bsdiff) +{ + g_free (bsdiff->from_checksum); + g_free (bsdiff); +} + +/* Load a content object, uncompressing it to an unlinked tmpfile + that's mmap()'d and suitable for seeking. + */ +static gboolean +get_unpacked_unlinked_content (OstreeRepo *repo, + const char *checksum, + GBytes **out_content, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GInputStream) istream = NULL; + + if (!ostree_repo_load_file (repo, checksum, &istream, NULL, NULL, + cancellable, error)) + return FALSE; + + *out_content = ot_map_anonymous_tmpfile_from_content (istream, cancellable, error); + if (!*out_content) + return FALSE; + return TRUE; +} + +static gboolean +try_content_bsdiff (OstreeRepo *repo, + const char *from, + const char *to, + ContentBsdiff **out_bsdiff, + guint64 max_bsdiff_size_bytes, + GCancellable *cancellable, + GError **error) +{ + + + g_autoptr(GFileInfo) from_finfo = NULL; + if (!ostree_repo_load_file (repo, from, NULL, &from_finfo, NULL, + cancellable, error)) + return FALSE; + g_autoptr(GFileInfo) to_finfo = NULL; + if (!ostree_repo_load_file (repo, to, NULL, &to_finfo, NULL, + cancellable, error)) + return FALSE; + + *out_bsdiff = NULL; + + /* Ignore this if it's too large */ + if (g_file_info_get_size (to_finfo) + g_file_info_get_size (from_finfo) > max_bsdiff_size_bytes) + return TRUE; + + ContentBsdiff *ret_bsdiff = g_new0 (ContentBsdiff, 1); + ret_bsdiff->from_checksum = g_strdup (from); + + ot_transfer_out_value (out_bsdiff, &ret_bsdiff); + return TRUE; +} + +static gboolean +try_content_rollsum (OstreeRepo *repo, + DeltaOpts opts, + const char *from, + const char *to, + ContentRollsum **out_rollsum, + GCancellable *cancellable, + GError **error) +{ + *out_rollsum = NULL; + + /* Load the content objects, splice them to uncompressed temporary files that + * we can just mmap() and seek around in conveniently. + */ + g_autoptr(GBytes) tmp_from = NULL; + if (!get_unpacked_unlinked_content (repo, from, &tmp_from, cancellable, error)) + return FALSE; + g_autoptr(GBytes) tmp_to = NULL; + if (!get_unpacked_unlinked_content (repo, to, &tmp_to, cancellable, error)) + return FALSE; + + OstreeRollsumMatches *matches = _ostree_compute_rollsum_matches (tmp_from, tmp_to); + + const guint match_ratio = (matches->bufmatches*100)/matches->total; + + /* Only proceed if the file contains (arbitrary) more than 50% of + * the previous chunks. + */ + if (match_ratio < 50) + return TRUE; + + if (opts & DELTAOPT_FLAG_VERBOSE) + { + g_printerr ("rollsum for %s -> %s; crcs=%u bufs=%u total=%u matchsize=%llu\n", + from, to, matches->crcmatches, + matches->bufmatches, + matches->total, (unsigned long long)matches->match_size); + } + + ContentRollsum *ret_rollsum = g_new0 (ContentRollsum, 1); + ret_rollsum->from_checksum = g_strdup (from); + ret_rollsum->matches = g_steal_pointer (&matches); + ot_transfer_out_value (out_rollsum, &ret_rollsum); + return TRUE; +} + +struct bzdiff_opaque_s +{ + GOutputStream *out; + GCancellable *cancellable; + GError **error; +}; + +static int +bzdiff_write (struct bsdiff_stream* stream, const void* buffer, int size) +{ + struct bzdiff_opaque_s *op = stream->opaque; + if (!g_output_stream_write (op->out, + buffer, + size, + op->cancellable, + op->error)) + return -1; + + return 0; +} + +static void +append_payload_chunk_and_write (OstreeStaticDeltaPartBuilder *current_part, + const guint8 *buf, + guint64 offset) +{ + guint64 payload_start; + + payload_start = current_part->payload->len; + g_string_append_len (current_part->payload, (char*)buf, offset); + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_WRITE); + _ostree_write_varuint64 (current_part->operations, offset); + _ostree_write_varuint64 (current_part->operations, payload_start); +} + +static gboolean +process_one_rollsum (OstreeRepo *repo, + OstreeStaticDeltaBuilder *builder, + OstreeStaticDeltaPartBuilder **current_part_val, + const char *to_checksum, + ContentRollsum *rollsum, + GCancellable *cancellable, + GError **error) +{ + OstreeStaticDeltaPartBuilder *current_part = *current_part_val; + + /* Check to see if this delta has gone over maximum size */ + if (current_part->objects->len > 0 && + current_part->payload->len > builder->max_chunk_size_bytes) + { + current_part = allocate_part (builder, error); + if (current_part == NULL) + return FALSE; + *current_part_val = current_part; + } + + g_autoptr(GBytes) tmp_to = NULL; + if (!get_unpacked_unlinked_content (repo, to_checksum, &tmp_to, + cancellable, error)) + return FALSE; + + gsize tmp_to_len; + const guint8 *tmp_to_buf = g_bytes_get_data (tmp_to, &tmp_to_len); + + g_autoptr(GFileInfo) content_finfo = NULL; + g_autoptr(GVariant) content_xattrs = NULL; + if (!ostree_repo_load_file (repo, to_checksum, NULL, + &content_finfo, &content_xattrs, + cancellable, error)) + return FALSE; + guint64 content_size = g_file_info_get_size (content_finfo); + g_assert_cmpint (tmp_to_len, ==, content_size); + + current_part->uncompressed_size += content_size; + + g_ptr_array_add (current_part->objects, ostree_object_name_serialize (to_checksum, OSTREE_OBJECT_TYPE_FILE)); + + { gsize mode_offset, xattr_offset, from_csum_offset; + gboolean reading_payload = TRUE; + guchar source_csum[OSTREE_SHA256_DIGEST_LEN]; + guint i; + + write_content_mode_xattrs (repo, current_part, content_finfo, content_xattrs, + &mode_offset, &xattr_offset); + + /* Write the origin checksum */ + ostree_checksum_inplace_to_bytes (rollsum->from_checksum, source_csum); + from_csum_offset = current_part->payload->len; + g_string_append_len (current_part->payload, (char*)source_csum, sizeof (source_csum)); + + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_OPEN); + _ostree_write_varuint64 (current_part->operations, mode_offset); + _ostree_write_varuint64 (current_part->operations, xattr_offset); + _ostree_write_varuint64 (current_part->operations, content_size); + + { guint64 writing_offset = 0; + guint64 offset = 0, to_start = 0, from_start = 0; + GPtrArray *matchlist = rollsum->matches->matches; + + g_assert (matchlist->len > 0); + for (i = 0; i < matchlist->len; i++) + { + GVariant *match = matchlist->pdata[i]; + guint32 crc; + + g_variant_get (match, "(uttt)", &crc, &offset, &to_start, &from_start); + + const guint64 prefix = to_start - writing_offset; + + if (prefix > 0) + { + if (!reading_payload) + { + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE); + reading_payload = TRUE; + } + + g_assert_cmpint (writing_offset + prefix, <=, tmp_to_len); + append_payload_chunk_and_write (current_part, tmp_to_buf + writing_offset, prefix); + writing_offset += prefix; + } + + if (reading_payload) + { + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE); + _ostree_write_varuint64 (current_part->operations, from_csum_offset); + reading_payload = FALSE; + } + + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_WRITE); + _ostree_write_varuint64 (current_part->operations, offset); + _ostree_write_varuint64 (current_part->operations, from_start); + writing_offset += offset; + } + + if (!reading_payload) + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE); + + const guint64 remainder = tmp_to_len - writing_offset; + if (remainder > 0) + append_payload_chunk_and_write (current_part, tmp_to_buf + writing_offset, remainder); + writing_offset += remainder; + g_assert_cmpint (writing_offset, ==, tmp_to_len); + g_assert_cmpint (writing_offset, ==, content_size); + } + + + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_CLOSE); + } + + return TRUE; +} + +static gboolean +process_one_bsdiff (OstreeRepo *repo, + OstreeStaticDeltaBuilder *builder, + OstreeStaticDeltaPartBuilder **current_part_val, + const char *to_checksum, + ContentBsdiff *bsdiff_content, + GCancellable *cancellable, + GError **error) +{ + OstreeStaticDeltaPartBuilder *current_part = *current_part_val; + + /* Check to see if this delta has gone over maximum size */ + if (current_part->objects->len > 0 && + current_part->payload->len > builder->max_chunk_size_bytes) + { + current_part = allocate_part (builder, error); + if (current_part == NULL) + return FALSE; + *current_part_val = current_part; + } + + g_autoptr(GBytes) tmp_from = NULL; + if (!get_unpacked_unlinked_content (repo, bsdiff_content->from_checksum, &tmp_from, + cancellable, error)) + return FALSE; + g_autoptr(GBytes) tmp_to = NULL; + if (!get_unpacked_unlinked_content (repo, to_checksum, &tmp_to, + cancellable, error)) + return FALSE; + + gsize tmp_to_len; + const guint8 *tmp_to_buf = g_bytes_get_data (tmp_to, &tmp_to_len); + gsize tmp_from_len; + const guint8 *tmp_from_buf = g_bytes_get_data (tmp_from, &tmp_from_len); + + g_autoptr(GFileInfo) content_finfo = NULL; + g_autoptr(GVariant) content_xattrs = NULL; + if (!ostree_repo_load_file (repo, to_checksum, NULL, + &content_finfo, &content_xattrs, + cancellable, error)) + return FALSE; + const guint64 content_size = g_file_info_get_size (content_finfo); + g_assert_cmpint (tmp_to_len, ==, content_size); + + current_part->uncompressed_size += content_size; + + g_ptr_array_add (current_part->objects, ostree_object_name_serialize (to_checksum, OSTREE_OBJECT_TYPE_FILE)); + + { gsize mode_offset, xattr_offset; + guchar source_csum[OSTREE_SHA256_DIGEST_LEN]; + + write_content_mode_xattrs (repo, current_part, content_finfo, content_xattrs, + &mode_offset, &xattr_offset); + + /* Write the origin checksum */ + ostree_checksum_inplace_to_bytes (bsdiff_content->from_checksum, source_csum); + + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE); + _ostree_write_varuint64 (current_part->operations, current_part->payload->len); + g_string_append_len (current_part->payload, (char*)source_csum, sizeof (source_csum)); + + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_OPEN); + _ostree_write_varuint64 (current_part->operations, mode_offset); + _ostree_write_varuint64 (current_part->operations, xattr_offset); + _ostree_write_varuint64 (current_part->operations, content_size); + + { + struct bsdiff_stream stream; + struct bzdiff_opaque_s op; + const gchar *payload; + gssize payload_size; + g_autoptr(GOutputStream) out = g_memory_output_stream_new_resizable (); + stream.malloc = malloc; + stream.free = free; + stream.write = bzdiff_write; + op.out = out; + op.cancellable = cancellable; + op.error = error; + stream.opaque = &op; + if (bsdiff (tmp_from_buf, tmp_from_len, tmp_to_buf, tmp_to_len, &stream) < 0) + return glnx_throw (error, "bsdiff generation failed"); + + payload = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (out)); + payload_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (out)); + + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_BSPATCH); + _ostree_write_varuint64 (current_part->operations, current_part->payload->len); + _ostree_write_varuint64 (current_part->operations, payload_size); + + /* A bit too verbose to print by default...but leaving this #if 0'd out to + * use later. One approach I've been thinking about is to optionally + * output e.g. a JSON file as we build the deltas. Alternatively, we could + * try to reverse engineer things more in the "show" path, but that gets + * hard/messy as it's quite optimized for execution now. + */ +#if 0 + g_printerr ("bspatch %s [%llu] → %s [%llu] bsdiff:%llu (%f)\n", + bsdiff_content->from_checksum, (unsigned long long)tmp_from_len, + to_checksum, (unsigned long long)tmp_to_len, + (unsigned long long)payload_size, + ((double)payload_size)/tmp_to_len); +#endif + + g_string_append_len (current_part->payload, payload, payload_size); + } + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_CLOSE); + } + + g_string_append_c (current_part->operations, (gchar)OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE); + + return TRUE; +} + +static gboolean +check_object_world_readable (OstreeRepo *repo, + const char *checksum, + gboolean *out_readable, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GFileInfo) finfo = NULL; + guint32 mode; + + if (!ostree_repo_load_file (repo, checksum, NULL, &finfo, NULL, + cancellable, error)) + return FALSE; + + mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode"); + *out_readable = (mode & S_IROTH); + return TRUE; +} + +static gboolean +generate_delta_lowlatency (OstreeRepo *repo, + const char *from, + const char *to, + DeltaOpts opts, + OstreeStaticDeltaBuilder *builder, + GCancellable *cancellable, + GError **error) +{ + GHashTableIter hashiter; + gpointer key, value; + OstreeStaticDeltaPartBuilder *current_part = NULL; + g_autoptr(GFile) root_from = NULL; + g_autoptr(GVariant) from_commit = NULL; + g_autoptr(GFile) root_to = NULL; + g_autoptr(GVariant) to_commit = NULL; + g_autoptr(GHashTable) to_reachable_objects = NULL; + g_autoptr(GHashTable) from_reachable_objects = NULL; + g_autoptr(GHashTable) new_reachable_metadata = NULL; + g_autoptr(GHashTable) new_reachable_regfile_content = NULL; + g_autoptr(GHashTable) new_reachable_symlink_content = NULL; + g_autoptr(GHashTable) modified_regfile_content = NULL; + g_autoptr(GHashTable) rollsum_optimized_content_objects = NULL; + g_autoptr(GHashTable) bsdiff_optimized_content_objects = NULL; + + if (from != NULL) + { + if (!ostree_repo_read_commit (repo, from, &root_from, NULL, + cancellable, error)) + return FALSE; + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, from, + &from_commit, error)) + return FALSE; + + if (!ostree_repo_traverse_commit (repo, from, 0, &from_reachable_objects, + cancellable, error)) + return FALSE; + } + + if (!ostree_repo_read_commit (repo, to, &root_to, NULL, + cancellable, error)) + return FALSE; + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, to, + &to_commit, error)) + return FALSE; + + if (!ostree_repo_traverse_commit (repo, to, 0, &to_reachable_objects, + cancellable, error)) + return FALSE; + + new_reachable_metadata = ostree_repo_traverse_new_reachable (); + new_reachable_regfile_content = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); + new_reachable_symlink_content = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); + + g_hash_table_iter_init (&hashiter, to_reachable_objects); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + GVariant *serialized_key = key; + const char *checksum; + OstreeObjectType objtype; + + if (from_reachable_objects && g_hash_table_contains (from_reachable_objects, serialized_key)) + continue; + + ostree_object_name_deserialize (serialized_key, &checksum, &objtype); + + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + g_hash_table_add (new_reachable_metadata, g_variant_ref (serialized_key)); + else + { + g_autoptr(GFileInfo) finfo = NULL; + GFileType ftype; + + if (!ostree_repo_load_file (repo, checksum, NULL, &finfo, NULL, + cancellable, error)) + return FALSE; + + ftype = g_file_info_get_file_type (finfo); + if (ftype == G_FILE_TYPE_REGULAR) + g_hash_table_add (new_reachable_regfile_content, g_strdup (checksum)); + else if (ftype == G_FILE_TYPE_SYMBOLIC_LINK) + g_hash_table_add (new_reachable_symlink_content, g_strdup (checksum)); + else + g_assert_not_reached (); + } + } + + if (from_commit) + { + if (!_ostree_delta_compute_similar_objects (repo, from_commit, to_commit, + new_reachable_regfile_content, + CONTENT_SIZE_SIMILARITY_THRESHOLD_PERCENT, + &modified_regfile_content, + cancellable, error)) + return FALSE; + } + else + modified_regfile_content = g_hash_table_new (g_str_hash, g_str_equal); + + if (opts & DELTAOPT_FLAG_VERBOSE) + { + g_printerr ("modified: %u\n", g_hash_table_size (modified_regfile_content)); + g_printerr ("new reachable: metadata=%u content regular=%u symlink=%u\n", + g_hash_table_size (new_reachable_metadata), + g_hash_table_size (new_reachable_regfile_content), + g_hash_table_size (new_reachable_symlink_content)); + } + + /* We already ship the to commit in the superblock, don't ship it twice */ + { g_autoptr(GVariant) commit = ostree_object_name_serialize (to, OSTREE_OBJECT_TYPE_COMMIT); + g_hash_table_remove (new_reachable_metadata, commit); + } + + rollsum_optimized_content_objects = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + (GDestroyNotify) content_rollsums_free); + + bsdiff_optimized_content_objects = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + (GDestroyNotify) content_bsdiffs_free); + + g_hash_table_iter_init (&hashiter, modified_regfile_content); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + const char *to_checksum = key; + const char *from_checksum = value; + ContentRollsum *rollsum; + ContentBsdiff *bsdiff; + gboolean from_world_readable = FALSE; + + /* We only want to include in the delta objects that we are sure will + * be readable by the client when applying the delta, regardless its + * access privileges, so that we don't run into permissions problems + * when the client is trying to update a bare-user repository with a + * bare repository defined as its parent. + */ + if (!check_object_world_readable (repo, from_checksum, &from_world_readable, cancellable, error)) + return FALSE; + if (!from_world_readable) + continue; + + if (!try_content_rollsum (repo, opts, from_checksum, to_checksum, + &rollsum, cancellable, error)) + return FALSE; + + if (rollsum) + { + g_hash_table_insert (rollsum_optimized_content_objects, g_strdup (to_checksum), rollsum); + builder->rollsum_size += rollsum->matches->match_size; + continue; + } + + if (!(opts & DELTAOPT_FLAG_DISABLE_BSDIFF)) + { + if (!try_content_bsdiff (repo, from_checksum, to_checksum, + &bsdiff, builder->max_bsdiff_size_bytes, + cancellable, error)) + return FALSE; + + if (bsdiff) + g_hash_table_insert (bsdiff_optimized_content_objects, g_strdup (to_checksum), bsdiff); + } + } + + if (opts & DELTAOPT_FLAG_VERBOSE) + { + g_printerr ("rollsum for %u/%u modified\n", + g_hash_table_size (rollsum_optimized_content_objects), + g_hash_table_size (modified_regfile_content)); + } + + current_part = allocate_part (builder, error); + if (current_part == NULL) + return FALSE; + + /* Pack the metadata first */ + g_hash_table_iter_init (&hashiter, new_reachable_metadata); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + GVariant *serialized_key = key; + const char *checksum; + OstreeObjectType objtype; + + ostree_object_name_deserialize (serialized_key, &checksum, &objtype); + + if (!process_one_object (repo, builder, ¤t_part, + checksum, objtype, + cancellable, error)) + return FALSE; + } + + /* Now do rollsummed objects */ + + g_hash_table_iter_init (&hashiter, rollsum_optimized_content_objects); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + const char *checksum = key; + ContentRollsum *rollsum = value; + + if (!process_one_rollsum (repo, builder, ¤t_part, + checksum, rollsum, + cancellable, error)) + return FALSE; + + builder->n_rollsum++; + } + + /* Now do bsdiff'ed objects */ + + const guint n_bsdiff = g_hash_table_size (bsdiff_optimized_content_objects); + if (n_bsdiff > 0) + { + const guint mod = n_bsdiff / 10; + g_hash_table_iter_init (&hashiter, bsdiff_optimized_content_objects); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + const char *checksum = key; + ContentBsdiff *bsdiff = value; + + if (opts & DELTAOPT_FLAG_VERBOSE && + (mod == 0 || builder->n_bsdiff % mod == 0)) + g_printerr ("processing bsdiff: [%u/%u]\n", builder->n_bsdiff, n_bsdiff); + + if (!process_one_bsdiff (repo, builder, ¤t_part, + checksum, bsdiff, + cancellable, error)) + return FALSE; + + builder->n_bsdiff++; + } + } + + /* Scan for large objects, so we can fall back to plain HTTP-based + * fetch. + */ + g_hash_table_iter_init (&hashiter, new_reachable_regfile_content); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + const char *checksum = key; + guint64 uncompressed_size; + gboolean fallback = FALSE; + + /* Skip content objects we rollsum'd or bsdiff'ed */ + if (g_hash_table_contains (rollsum_optimized_content_objects, checksum) || + g_hash_table_contains (bsdiff_optimized_content_objects, checksum)) + continue; + + if (!ostree_repo_load_object_stream (repo, OSTREE_OBJECT_TYPE_FILE, checksum, + NULL, &uncompressed_size, + cancellable, error)) + return FALSE; + if (builder->min_fallback_size_bytes > 0 && + uncompressed_size > builder->min_fallback_size_bytes) + fallback = TRUE; + + if (fallback) + { + g_autofree char *size = g_format_size (uncompressed_size); + + if (opts & DELTAOPT_FLAG_VERBOSE) + g_printerr ("fallback for %s (%s)\n", checksum, size); + + g_ptr_array_add (builder->fallback_objects, + ostree_object_name_serialize (checksum, OSTREE_OBJECT_TYPE_FILE)); + g_hash_table_iter_remove (&hashiter); + builder->n_fallback++; + } + } + + /* Now non-rollsummed or bsdiff'ed regular file content */ + g_hash_table_iter_init (&hashiter, new_reachable_regfile_content); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + const char *checksum = key; + + /* Skip content objects we rollsum'd */ + if (g_hash_table_contains (rollsum_optimized_content_objects, checksum) || + g_hash_table_contains (bsdiff_optimized_content_objects, checksum)) + continue; + + if (!process_one_object (repo, builder, ¤t_part, + checksum, OSTREE_OBJECT_TYPE_FILE, + cancellable, error)) + return FALSE; + } + + /* Now symlinks */ + g_hash_table_iter_init (&hashiter, new_reachable_symlink_content); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + const char *checksum = key; + + if (!process_one_object (repo, builder, ¤t_part, + checksum, OSTREE_OBJECT_TYPE_FILE, + cancellable, error)) + return FALSE; + } + + if (!finish_part (builder, error)) + return FALSE; + + return TRUE; +} + +static gboolean +get_fallback_headers (OstreeRepo *self, + OstreeStaticDeltaBuilder *builder, + GVariant **out_headers, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariantBuilder) fallback_builder = + g_variant_builder_new (G_VARIANT_TYPE ("a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT)); + + for (guint i = 0; i < builder->fallback_objects->len; i++) + { + GVariant *serialized = builder->fallback_objects->pdata[i]; + const char *checksum; + OstreeObjectType objtype; + guint64 compressed_size; + guint64 uncompressed_size; + + ostree_object_name_deserialize (serialized, &checksum, &objtype); + + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + { + if (!ostree_repo_load_object_stream (self, objtype, checksum, + NULL, &uncompressed_size, + cancellable, error)) + return FALSE; + compressed_size = uncompressed_size; + } + else + { + if (!ostree_repo_query_object_storage_size (self, OSTREE_OBJECT_TYPE_FILE, + checksum, + &compressed_size, + cancellable, error)) + return FALSE; + + g_autoptr(GFileInfo) file_info = NULL; + if (!ostree_repo_load_file (self, checksum, + NULL, &file_info, NULL, + cancellable, error)) + return FALSE; + + uncompressed_size = g_file_info_get_size (file_info); + } + + g_variant_builder_add_value (fallback_builder, + g_variant_new ("(y@aytt)", + objtype, + ostree_checksum_to_bytes_v (checksum), + maybe_swap_endian_u64 (builder->swap_endian, compressed_size), + maybe_swap_endian_u64 (builder->swap_endian, uncompressed_size))); + } + + g_autoptr(GVariant) ret_headers = g_variant_ref_sink (g_variant_builder_end (fallback_builder)); + ot_transfer_out_value (out_headers, &ret_headers); + return TRUE; +} + +/** + * ostree_repo_static_delta_generate: + * @self: Repo + * @opt: High level optimization choice + * @from: ASCII SHA256 checksum of origin, or %NULL + * @to: ASCII SHA256 checksum of target + * @metadata: (allow-none): Optional metadata + * @params: (allow-none): Parameters, see below + * @cancellable: Cancellable + * @error: Error + * + * Generate a lookaside "static delta" from @from (%NULL means + * from-empty) which can generate the objects in @to. This delta is + * an optimization over fetching individual objects, and can be + * conveniently stored and applied offline. + * + * The @params argument should be an a{sv}. The following attributes + * are known: + * - min-fallback-size: u: Minimum uncompressed size in megabytes to use fallback, 0 to disable fallbacks + * - max-chunk-size: u: Maximum size in megabytes of a delta part + * - max-bsdiff-size: u: Maximum size in megabytes to consider bsdiff compression + * for input files + * - compression: y: Compression type: 0=none, x=lzma, g=gzip + * - bsdiff-enabled: b: Enable bsdiff compression. Default TRUE. + * - inline-parts: b: Put part data in header, to get a single file delta. Default FALSE. + * - verbose: b: Print diagnostic messages. Default FALSE. + * - endianness: b: Deltas use host byte order by default; this option allows choosing (G_BIG_ENDIAN or G_LITTLE_ENDIAN) + * - filename: ay: Save delta superblock to this filename, and parts in the same directory. Default saves to repository. + */ +gboolean +ostree_repo_static_delta_generate (OstreeRepo *self, + OstreeStaticDeltaGenerateOpt opt, + const char *from, + const char *to, + GVariant *metadata, + GVariant *params, + GCancellable *cancellable, + GError **error) +{ + OstreeStaticDeltaBuilder builder = { 0, }; + guint i; + guint min_fallback_size; + guint max_bsdiff_size; + guint max_chunk_size; + DeltaOpts delta_opts = DELTAOPT_FLAG_NONE; + guint64 total_compressed_size = 0; + guint64 total_uncompressed_size = 0; + g_autoptr(GVariantBuilder) part_headers = NULL; + g_autoptr(GPtrArray) part_temp_paths = NULL; + g_autoptr(GVariant) to_commit = NULL; + const char *opt_filename; + g_autofree char *descriptor_name = NULL; + glnx_autofd int descriptor_dfd = -1; + g_autoptr(GVariant) fallback_headers = NULL; + g_autoptr(GVariant) detached = NULL; + gboolean inline_parts; + guint endianness = G_BYTE_ORDER; + g_autoptr(GPtrArray) builder_parts = g_ptr_array_new_with_free_func ((GDestroyNotify)ostree_static_delta_part_builder_unref); + g_autoptr(GPtrArray) builder_fallback_objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); + g_auto(GLnxTmpfile) descriptor_tmpf = { 0, }; + g_autoptr(OtVariantBuilder) descriptor_builder = NULL; + + if (!g_variant_lookup (params, "min-fallback-size", "u", &min_fallback_size)) + min_fallback_size = 4; + builder.min_fallback_size_bytes = ((guint64)min_fallback_size) * 1000 * 1000; + + if (!g_variant_lookup (params, "max-bsdiff-size", "u", &max_bsdiff_size)) + max_bsdiff_size = 128; + builder.max_bsdiff_size_bytes = ((guint64)max_bsdiff_size) * 1000 * 1000; + if (!g_variant_lookup (params, "max-chunk-size", "u", &max_chunk_size)) + max_chunk_size = 32; + builder.max_chunk_size_bytes = ((guint64)max_chunk_size) * 1000 * 1000; + + (void) g_variant_lookup (params, "endianness", "u", &endianness); + g_return_val_if_fail (endianness == G_BIG_ENDIAN || endianness == G_LITTLE_ENDIAN, FALSE); + + builder.swap_endian = endianness != G_BYTE_ORDER; + builder.parts = builder_parts; + builder.fallback_objects = builder_fallback_objects; + + { gboolean use_bsdiff; + if (!g_variant_lookup (params, "bsdiff-enabled", "b", &use_bsdiff)) + use_bsdiff = TRUE; + if (!use_bsdiff) + delta_opts |= DELTAOPT_FLAG_DISABLE_BSDIFF; + } + + { gboolean verbose; + if (!g_variant_lookup (params, "verbose", "b", &verbose)) + verbose = FALSE; + if (verbose) + delta_opts |= DELTAOPT_FLAG_VERBOSE; + } + + if (!g_variant_lookup (params, "inline-parts", "b", &inline_parts)) + inline_parts = FALSE; + + if (!g_variant_lookup (params, "filename", "^&ay", &opt_filename)) + opt_filename = NULL; + + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, to, + &to_commit, error)) + return FALSE; + + builder.delta_opts = delta_opts; + + if (opt_filename) + { + g_autofree char *dnbuf = g_strdup (opt_filename); + const char *dn = dirname (dnbuf); + descriptor_name = g_strdup (glnx_basename (opt_filename)); + + if (!glnx_opendirat (AT_FDCWD, dn, TRUE, &descriptor_dfd, error)) + return FALSE; + } + else + { + g_autofree char *descriptor_relpath = _ostree_get_relative_static_delta_superblock_path (from, to); + g_autofree char *dnbuf = g_strdup (descriptor_relpath); + const char *dn = dirname (dnbuf); + + if (!glnx_shutil_mkdir_p_at (self->repo_dir_fd, dn, DEFAULT_DIRECTORY_MODE, cancellable, error)) + return FALSE; + if (!glnx_opendirat (self->repo_dir_fd, dn, TRUE, &descriptor_dfd, error)) + return FALSE; + + descriptor_name = g_strdup (basename (descriptor_relpath)); + } + builder.parts_dfd = descriptor_dfd; + + /* Ignore optimization flags */ + if (!generate_delta_lowlatency (self, from, to, delta_opts, &builder, + cancellable, error)) + return FALSE; + + if (!glnx_open_tmpfile_linkable_at (descriptor_dfd, ".", O_WRONLY | O_CLOEXEC, + &descriptor_tmpf, error)) + return FALSE; + + descriptor_builder = ot_variant_builder_new (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), descriptor_tmpf.fd); + + /* Open the metadata dict */ + if (!ot_variant_builder_open (descriptor_builder, G_VARIANT_TYPE ("a{sv}"), error)) + return FALSE; + + /* NOTE: Add user-supplied metadata first. This is used by at least + * flatpak as a way to provide MIME content sniffing, since the + * metadata appears first in the file. + */ + if (metadata != NULL) + { + GVariantIter iter; + GVariant *item; + + g_variant_iter_init (&iter, metadata); + while ((item = g_variant_iter_next_value (&iter))) + { + if (!ot_variant_builder_add_value (descriptor_builder, item, error)) + return FALSE; + g_variant_unref (item); + } + } + + { guint8 endianness_char; + + switch (endianness) + { + case G_LITTLE_ENDIAN: + endianness_char = 'l'; + break; + case G_BIG_ENDIAN: + endianness_char = 'B'; + break; + default: + g_assert_not_reached (); + } + if (!ot_variant_builder_add (descriptor_builder, error, "{sv}", "ostree.endianness", g_variant_new_byte (endianness_char))) + return FALSE; + } + + part_headers = g_variant_builder_new (G_VARIANT_TYPE ("a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT)); + part_temp_paths = g_ptr_array_new_with_free_func ((GDestroyNotify)glnx_tmpfile_clear); + for (i = 0; i < builder.parts->len; i++) + { + OstreeStaticDeltaPartBuilder *part_builder = builder.parts->pdata[i]; + + if (inline_parts) + { + g_autofree char *part_relpath = _ostree_get_relative_static_delta_part_path (from, to, i); + + lseek (part_builder->part_tmpf.fd, 0, SEEK_SET); + + if (!ot_variant_builder_open (descriptor_builder, G_VARIANT_TYPE ("{sv}"), error) || + !ot_variant_builder_add (descriptor_builder, error, "s", part_relpath) || + !ot_variant_builder_open (descriptor_builder, G_VARIANT_TYPE ("v"), error) || + !ot_variant_builder_add_from_fd (descriptor_builder, G_VARIANT_TYPE ("(yay)"), part_builder->part_tmpf.fd, part_builder->compressed_size, error) || + !ot_variant_builder_close (descriptor_builder, error) || + !ot_variant_builder_close (descriptor_builder, error)) + return FALSE; + } + else + { + g_autofree char *partstr = g_strdup_printf ("%u", i); + + if (fchmod (part_builder->part_tmpf.fd, 0644) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + if (!glnx_link_tmpfile_at (&part_builder->part_tmpf, GLNX_LINK_TMPFILE_REPLACE, + descriptor_dfd, partstr, error)) + return FALSE; + } + + g_variant_builder_add_value (part_headers, part_builder->header); + + total_compressed_size += part_builder->compressed_size; + total_uncompressed_size += part_builder->uncompressed_size; + } + + if (!get_fallback_headers (self, &builder, &fallback_headers, + cancellable, error)) + return FALSE; + + if (!ostree_repo_read_commit_detached_metadata (self, to, &detached, cancellable, error)) + return FALSE; + + if (detached) + { + g_autofree char *detached_key = _ostree_get_relative_static_delta_path (from, to, "commitmeta"); + if (!ot_variant_builder_add (descriptor_builder, error, "{sv}", detached_key, detached)) + return FALSE; + } + + /* Close metadata dict */ + if (!ot_variant_builder_close (descriptor_builder, error)) + return FALSE; + + /* Generate OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT */ + { + GDateTime *now = g_date_time_new_now_utc (); + /* floating */ GVariant *from_csum_v = + from ? ostree_checksum_to_bytes_v (from) : ot_gvariant_new_bytearray ((guchar *)"", 0); + /* floating */ GVariant *to_csum_v = + ostree_checksum_to_bytes_v (to); + + + if (!ot_variant_builder_add (descriptor_builder, error, "t", + GUINT64_TO_BE (g_date_time_to_unix (now))) || + !ot_variant_builder_add_value (descriptor_builder, + from_csum_v, error) || + !ot_variant_builder_add_value (descriptor_builder, + to_csum_v, error) || + !ot_variant_builder_add_value (descriptor_builder, + to_commit, error) || + !ot_variant_builder_add_value (descriptor_builder, + ot_gvariant_new_bytearray ((guchar*)"", 0), error) || + !ot_variant_builder_add_value (descriptor_builder, + g_variant_builder_end (part_headers), error) || + !ot_variant_builder_add_value (descriptor_builder, + fallback_headers, error)) + return FALSE; + + if (!ot_variant_builder_end (descriptor_builder, error)) + return FALSE; + + g_date_time_unref (now); + } + + if (delta_opts & DELTAOPT_FLAG_VERBOSE) + { + g_printerr ("uncompressed=%" G_GUINT64_FORMAT " compressed=%" G_GUINT64_FORMAT " loose=%" G_GUINT64_FORMAT "\n", + total_uncompressed_size, + total_compressed_size, + builder.loose_compressed_size); + g_printerr ("rollsum=%u objects, %" G_GUINT64_FORMAT " bytes\n", + builder.n_rollsum, + builder.rollsum_size); + g_printerr ("bsdiff=%u objects\n", builder.n_bsdiff); + } + + if (fchmod (descriptor_tmpf.fd, 0644) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + if (!glnx_link_tmpfile_at (&descriptor_tmpf, GLNX_LINK_TMPFILE_REPLACE, + descriptor_dfd, descriptor_name, error)) + return FALSE; + + return TRUE; +} diff --git a/src/libostree/ostree-repo-static-delta-core.c b/src/libostree/ostree-repo-static-delta-core.c new file mode 100644 index 0000000..ade4e9d --- /dev/null +++ b/src/libostree/ostree-repo-static-delta-core.c @@ -0,0 +1,875 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include "ostree-core-private.h" +#include "ostree-repo-private.h" +#include "ostree-lzma-decompressor.h" +#include "ostree-cmdprivate.h" +#include "ostree-checksum-input-stream.h" +#include "ostree-repo-static-delta-private.h" +#include "otutil.h" + +gboolean +_ostree_static_delta_parse_checksum_array (GVariant *array, + guint8 **out_checksums_array, + guint *out_n_checksums, + GError **error) +{ + const gsize n = g_variant_n_children (array); + const guint n_checksums = n / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN; + + if (G_UNLIKELY(n > (G_MAXUINT32/OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN) || + (n_checksums * OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN) != n)) + { + return glnx_throw (error, + "Invalid checksum array length %" G_GSIZE_FORMAT, n); + } + + *out_checksums_array = (gpointer)g_variant_get_data (array); + *out_n_checksums = n_checksums; + + return TRUE; +} + + +/** + * ostree_repo_list_static_delta_names: + * @self: Repo + * @out_deltas: (out) (element-type utf8) (transfer container): String name of deltas (checksum-checksum.delta) + * @cancellable: Cancellable + * @error: Error + * + * This function synchronously enumerates all static deltas in the + * repository, returning its result in @out_deltas. + */ +gboolean +ostree_repo_list_static_delta_names (OstreeRepo *self, + GPtrArray **out_deltas, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GPtrArray) ret_deltas = g_ptr_array_new_with_free_func (g_free); + + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, "deltas", &dfd_iter, + &exists, error)) + return FALSE; + if (!exists) + { + /* Note early return */ + ot_transfer_out_value (out_deltas, &ret_deltas); + return TRUE; + } + + while (TRUE) + { + g_auto(GLnxDirFdIterator) sub_dfd_iter = { 0, }; + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + if (dent->d_type != DT_DIR) + continue; + + if (!glnx_dirfd_iterator_init_at (dfd_iter.fd, dent->d_name, FALSE, + &sub_dfd_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *sub_dent; + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&sub_dfd_iter, &sub_dent, + cancellable, error)) + return FALSE; + if (sub_dent == NULL) + break; + if (dent->d_type != DT_DIR) + continue; + + const char *name1 = dent->d_name; + const char *name2 = sub_dent->d_name; + + g_autofree char *superblock_subpath = g_strconcat (name2, "/superblock", NULL); + if (!glnx_fstatat_allow_noent (sub_dfd_iter.fd, superblock_subpath, NULL, 0, error)) + return FALSE; + if (errno == ENOENT) + continue; + + g_autofree char *buf = g_strconcat (name1, name2, NULL); + GString *out = g_string_new (""); + char checksum[OSTREE_SHA256_STRING_LEN+1]; + guchar csum[OSTREE_SHA256_DIGEST_LEN]; + const char *dash = strchr (buf, '-'); + + ostree_checksum_b64_inplace_to_bytes (buf, csum); + ostree_checksum_inplace_from_bytes (csum, checksum); + g_string_append (out, checksum); + if (dash) + { + g_string_append_c (out, '-'); + ostree_checksum_b64_inplace_to_bytes (dash+1, csum); + ostree_checksum_inplace_from_bytes (csum, checksum); + g_string_append (out, checksum); + } + + g_ptr_array_add (ret_deltas, g_string_free (out, FALSE)); + } + } + + ot_transfer_out_value (out_deltas, &ret_deltas); + return TRUE; +} + +gboolean +_ostree_repo_static_delta_part_have_all_objects (OstreeRepo *repo, + GVariant *checksum_array, + gboolean *out_have_all, + GCancellable *cancellable, + GError **error) +{ + guint8 *checksums_data = NULL; + guint n_checksums = 0; + gboolean have_object = TRUE; + + if (!_ostree_static_delta_parse_checksum_array (checksum_array, + &checksums_data, + &n_checksums, + error)) + return FALSE; + + for (guint i = 0; i < n_checksums; i++) + { + guint8 objtype = *checksums_data; + const guint8 *csum = checksums_data + 1; + char tmp_checksum[OSTREE_SHA256_STRING_LEN+1]; + + if (G_UNLIKELY(!ostree_validate_structureof_objtype (objtype, error))) + return FALSE; + + ostree_checksum_inplace_from_bytes (csum, tmp_checksum); + + if (!ostree_repo_has_object (repo, (OstreeObjectType) objtype, tmp_checksum, + &have_object, cancellable, error)) + return FALSE; + + if (!have_object) + break; + + checksums_data += OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN; + } + + *out_have_all = have_object; + return TRUE; +} + +/** + * ostree_repo_static_delta_execute_offline: + * @self: Repo + * @dir_or_file: Path to a directory containing static delta data, or directly to the superblock + * @skip_validation: If %TRUE, assume data integrity + * @cancellable: Cancellable + * @error: Error + * + * Given a directory representing an already-downloaded static delta + * on disk, apply it, generating a new commit. The directory must be + * named with the form "FROM-TO", where both are checksums, and it + * must contain a file named "superblock", along with at least one part. + */ +gboolean +ostree_repo_static_delta_execute_offline (OstreeRepo *self, + GFile *dir_or_file, + gboolean skip_validation, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *basename = NULL; + + const char *dir_or_file_path = gs_file_get_path_cached (dir_or_file); + + /* First, try opening it as a directory */ + glnx_autofd int dfd = glnx_opendirat_with_errno (AT_FDCWD, dir_or_file_path, TRUE); + if (dfd < 0) + { + if (errno != ENOTDIR) + return glnx_throw_errno_prefix (error, "openat(O_DIRECTORY)"); + else + { + g_autofree char *dir = dirname (g_strdup (dir_or_file_path)); + basename = g_path_get_basename (dir_or_file_path); + + if (!glnx_opendirat (AT_FDCWD, dir, TRUE, &dfd, error)) + return FALSE; + } + } + else + basename = g_strdup ("superblock"); + + glnx_autofd int meta_fd = openat (dfd, basename, O_RDONLY | O_CLOEXEC); + if (meta_fd < 0) + return glnx_throw_errno_prefix (error, "openat(%s)", basename); + + g_autoptr(GVariant) meta = NULL; + if (!ot_variant_read_fd (meta_fd, 0, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), + FALSE, &meta, error)) + return FALSE; + + /* Parsing OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT */ + + g_autoptr(GVariant) metadata = g_variant_get_child_value (meta, 0); + + g_autofree char *to_checksum = NULL; + g_autofree char *from_checksum = NULL; + /* Write the to-commit object */ + { + g_autoptr(GVariant) to_csum_v = NULL; + g_autoptr(GVariant) from_csum_v = NULL; + g_autoptr(GVariant) to_commit = NULL; + gboolean have_to_commit; + gboolean have_from_commit; + + to_csum_v = g_variant_get_child_value (meta, 3); + if (!ostree_validate_structureof_csum_v (to_csum_v, error)) + return FALSE; + to_checksum = ostree_checksum_from_bytes_v (to_csum_v); + + from_csum_v = g_variant_get_child_value (meta, 2); + if (g_variant_n_children (from_csum_v) > 0) + { + if (!ostree_validate_structureof_csum_v (from_csum_v, error)) + return FALSE; + from_checksum = ostree_checksum_from_bytes_v (from_csum_v); + + if (!ostree_repo_has_object (self, OSTREE_OBJECT_TYPE_COMMIT, from_checksum, + &have_from_commit, cancellable, error)) + return FALSE; + + if (!have_from_commit) + return glnx_throw (error, "Commit %s, which is the delta source, is not in repository", from_checksum); + } + + if (!ostree_repo_has_object (self, OSTREE_OBJECT_TYPE_COMMIT, to_checksum, + &have_to_commit, cancellable, error)) + return FALSE; + + if (!have_to_commit) + { + g_autofree char *detached_path = _ostree_get_relative_static_delta_path (from_checksum, to_checksum, "commitmeta"); + g_autoptr(GVariant) detached_data = NULL; + + detached_data = g_variant_lookup_value (metadata, detached_path, G_VARIANT_TYPE("a{sv}")); + if (detached_data && !ostree_repo_write_commit_detached_metadata (self, + to_checksum, + detached_data, + cancellable, + error)) + return FALSE; + + to_commit = g_variant_get_child_value (meta, 4); + if (!ostree_repo_write_metadata (self, OSTREE_OBJECT_TYPE_COMMIT, + to_checksum, to_commit, NULL, + cancellable, error)) + return FALSE; + } + } + + g_autoptr(GVariant) fallback = g_variant_get_child_value (meta, 7); + if (g_variant_n_children (fallback) > 0) + return glnx_throw (error, "Cannot execute delta offline: contains nonempty http fallback entries"); + + g_autoptr(GVariant) headers = g_variant_get_child_value (meta, 6); + const guint n = g_variant_n_children (headers); + for (guint i = 0; i < n; i++) + { + guint32 version; + guint64 size; + guint64 usize; + char checksum[OSTREE_SHA256_STRING_LEN+1]; + g_autoptr(GVariant) csum_v = NULL; + g_autoptr(GVariant) objects = NULL; + g_autoptr(GVariant) part = NULL; + OstreeStaticDeltaOpenFlags delta_open_flags = + skip_validation ? OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM : 0; + g_autoptr(GVariant) header = g_variant_get_child_value (headers, i); + g_variant_get (header, "(u@aytt@ay)", &version, &csum_v, &size, &usize, &objects); + + if (version > OSTREE_DELTAPART_VERSION) + return glnx_throw (error, "Delta part has too new version %u", version); + + gboolean have_all; + if (!_ostree_repo_static_delta_part_have_all_objects (self, objects, &have_all, + cancellable, error)) + return FALSE; + + /* If we already have these objects, don't bother executing the + * static delta. + */ + if (have_all) + continue; + + const guchar *csum = ostree_checksum_bytes_peek_validate (csum_v, error); + if (!csum) + return FALSE; + ostree_checksum_inplace_from_bytes (csum, checksum); + + g_autofree char *deltapart_path = + _ostree_get_relative_static_delta_part_path (from_checksum, to_checksum, i); + + g_autoptr(GInputStream) part_in = NULL; + g_autoptr(GVariant) inline_part_data = g_variant_lookup_value (metadata, deltapart_path, G_VARIANT_TYPE("(yay)")); + if (inline_part_data) + { + g_autoptr(GBytes) inline_part_bytes = g_variant_get_data_as_bytes (inline_part_data); + part_in = g_memory_input_stream_new_from_bytes (inline_part_bytes); + + /* For inline parts, we don't checksum, because it's + * included with the metadata, so we're not trying to + * protect against MITM or such. Non-security related + * checksums should be done at the underlying storage layer. + */ + delta_open_flags |= OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM; + + if (!_ostree_static_delta_part_open (part_in, inline_part_bytes, + delta_open_flags, + NULL, + &part, + cancellable, error)) + return FALSE; + } + else + { + g_autofree char *relpath = g_strdup_printf ("%u", i); /* TODO avoid malloc here */ + glnx_autofd int part_fd = openat (dfd, relpath, O_RDONLY | O_CLOEXEC); + if (part_fd < 0) + return glnx_throw_errno_prefix (error, "Opening deltapart '%s'", relpath); + + part_in = g_unix_input_stream_new (part_fd, FALSE); + + if (!_ostree_static_delta_part_open (part_in, NULL, + delta_open_flags, + checksum, + &part, + cancellable, error)) + return FALSE; + } + + if (!_ostree_static_delta_part_execute (self, objects, part, skip_validation, + NULL, cancellable, error)) + return glnx_prefix_error (error, "Executing delta part %i", i); + } + + return TRUE; +} + +gboolean +_ostree_static_delta_part_open (GInputStream *part_in, + GBytes *inline_part_bytes, + OstreeStaticDeltaOpenFlags flags, + const char *expected_checksum, + GVariant **out_part, + GCancellable *cancellable, + GError **error) +{ + const gboolean trusted = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED) > 0; + const gboolean skip_checksum = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM) > 0; + + /* We either take a fd or a GBytes reference */ + g_return_val_if_fail (G_IS_FILE_DESCRIPTOR_BASED (part_in) || inline_part_bytes != NULL, FALSE); + g_return_val_if_fail (skip_checksum || expected_checksum != NULL, FALSE); + + g_autoptr(GChecksum) checksum = NULL; + g_autoptr(GInputStream) checksum_in = NULL; + GInputStream *source_in; + if (!skip_checksum) + { + checksum = g_checksum_new (G_CHECKSUM_SHA256); + checksum_in = (GInputStream*)ostree_checksum_input_stream_new (part_in, checksum); + source_in = checksum_in; + } + else + { + source_in = part_in; + } + + guint8 comptype; + { guint8 buf[1]; + gsize bytes_read; + /* First byte is compression type */ + if (!g_input_stream_read_all (source_in, buf, sizeof(buf), &bytes_read, + cancellable, error)) + return glnx_prefix_error (error, "Reading initial compression flag byte"); + comptype = buf[0]; + } + + g_autoptr(GVariant) ret_part = NULL; + switch (comptype) + { + case 0: + if (!inline_part_bytes) + { + int part_fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)part_in); + + /* No compression, no checksums - a fast path */ + if (!ot_variant_read_fd (part_fd, 1, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), + trusted, &ret_part, error)) + return FALSE; + } + else + { + g_autoptr(GBytes) content_bytes = g_bytes_new_from_bytes (inline_part_bytes, 1, + g_bytes_get_size (inline_part_bytes) - 1); + ret_part = g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), + content_bytes, trusted); + g_variant_ref_sink (ret_part); + } + + if (!skip_checksum) + g_checksum_update (checksum, g_variant_get_data (ret_part), + g_variant_get_size (ret_part)); + + break; + case 'x': + { + g_autoptr(GConverter) decomp = (GConverter*) _ostree_lzma_decompressor_new (); + g_autoptr(GInputStream) convin = g_converter_input_stream_new (source_in, decomp); + g_autoptr(GBytes) buf = ot_map_anonymous_tmpfile_from_content (convin, cancellable, error); + if (!buf) + return FALSE; + + ret_part = g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), + buf, FALSE); + } + break; + default: + return glnx_throw (error, "Invalid compression type '%u'", comptype); + } + + if (checksum) + { + const char *actual_checksum = g_checksum_get_string (checksum); + g_assert (expected_checksum != NULL); + if (strcmp (actual_checksum, expected_checksum) != 0) + return glnx_throw (error, "Checksum mismatch in static delta part; expected=%s actual=%s", + expected_checksum, actual_checksum); + } + + *out_part = g_steal_pointer (&ret_part); + return TRUE; +} + +/* + * Displaying static delta parts + */ + +static gboolean +show_one_part (OstreeRepo *self, + gboolean swap_endian, + const char *from, + const char *to, + GVariant *meta_entries, + guint i, + guint64 *total_size_ref, + guint64 *total_usize_ref, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *part_path = _ostree_get_relative_static_delta_part_path (from, to, i); + + guint32 version; + guint64 size, usize; + g_autoptr(GVariant) objects = NULL; + g_variant_get_child (meta_entries, i, "(u@aytt@ay)", &version, NULL, &size, &usize, &objects); + size = maybe_swap_endian_u64 (swap_endian, size); + usize = maybe_swap_endian_u64 (swap_endian, usize); + *total_size_ref += size; + *total_usize_ref += usize; + g_print ("PartMeta%u: nobjects=%u size=%" G_GUINT64_FORMAT " usize=%" G_GUINT64_FORMAT "\n", + i, (guint)(g_variant_get_size (objects) / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN), size, usize); + + glnx_autofd int part_fd = openat (self->repo_dir_fd, part_path, O_RDONLY | O_CLOEXEC); + if (part_fd < 0) + return glnx_throw_errno_prefix (error, "openat(%s)", part_path); + g_autoptr(GInputStream) part_in = g_unix_input_stream_new (part_fd, FALSE); + + g_autoptr(GVariant) part = NULL; + if (!_ostree_static_delta_part_open (part_in, NULL, + OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM, + NULL, + &part, + cancellable, error)) + return FALSE; + + { g_autoptr(GVariant) modes = NULL; + g_autoptr(GVariant) xattrs = NULL; + g_autoptr(GVariant) blob = NULL; + g_autoptr(GVariant) ops = NULL; + OstreeDeltaExecuteStats stats = { { 0, }, }; + + g_variant_get (part, "(@a(uuu)@aa(ayay)@ay@ay)", + &modes, &xattrs, &blob, &ops); + + g_print ("PartPayload%u: nmodes=%" G_GUINT64_FORMAT + " nxattrs=%" G_GUINT64_FORMAT + " blobsize=%" G_GUINT64_FORMAT + " opsize=%" G_GUINT64_FORMAT + "\n", + i, + (guint64)g_variant_n_children (modes), + (guint64)g_variant_n_children (xattrs), + (guint64)g_variant_n_children (blob), + (guint64)g_variant_n_children (ops)); + + if (!_ostree_static_delta_part_execute (self, objects, + part, TRUE, + &stats, cancellable, error)) + return FALSE; + + { const guint *n_ops = stats.n_ops_executed; + g_print ("PartPayloadOps%u: openspliceclose=%u open=%u write=%u setread=%u " + "unsetread=%u close=%u bspatch=%u\n", + i, n_ops[0], n_ops[1], n_ops[2], n_ops[3], n_ops[4], n_ops[5], n_ops[6]); + } + } + + return TRUE; +} + +OstreeDeltaEndianness +_ostree_delta_get_endianness (GVariant *superblock, + gboolean *out_was_heuristic) +{ + g_autoptr(GVariant) delta_meta = g_variant_get_child_value (superblock, 0); + g_autoptr(GVariantDict) delta_metadict = g_variant_dict_new (delta_meta); + + if (out_was_heuristic) + *out_was_heuristic = FALSE; + + guint8 endianness_char; + if (g_variant_dict_lookup (delta_metadict, "ostree.endianness", "y", &endianness_char)) + { + switch (endianness_char) + { + case 'l': + return OSTREE_DELTA_ENDIAN_LITTLE; + case 'B': + return OSTREE_DELTA_ENDIAN_BIG; + default: + return OSTREE_DELTA_ENDIAN_INVALID; + } + } + + if (out_was_heuristic) + *out_was_heuristic = TRUE; + + guint64 total_size = 0; + guint64 total_usize = 0; + guint total_objects = 0; + { g_autoptr(GVariant) meta_entries = NULL; + gboolean is_byteswapped = FALSE; + + g_variant_get_child (superblock, 6, "@a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT, &meta_entries); + const guint n_parts = g_variant_n_children (meta_entries); + + for (guint i = 0; i < n_parts; i++) + { + g_autoptr(GVariant) objects = NULL; + guint64 size, usize; + guint n_objects; + + g_variant_get_child (meta_entries, i, "(u@aytt@ay)", NULL, NULL, &size, &usize, &objects); + n_objects = (guint)(g_variant_get_size (objects) / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN); + + total_objects += n_objects; + total_size += size; + total_usize += usize; + + if (size > usize) + { + double ratio = ((double)size)/((double)usize); + + /* This should really never happen where compressing things makes it more than 50% bigger. + */ + if (ratio > 1.2) + { + is_byteswapped = TRUE; + break; + } + } + } + + if (!is_byteswapped) + { + /* If the average object size is greater than 4GiB, let's assume + * we're dealing with opposite endianness. I'm fairly confident + * no one is going to be shipping peta- or exa- byte size ostree + * deltas, period. Past the gigabyte scale you really want + * bittorrent or something. + */ + if (total_objects > 0 && (total_size / total_objects) > G_MAXUINT32) + { + is_byteswapped = TRUE; + } + } + + if (is_byteswapped) + { + switch (G_BYTE_ORDER) + { + case G_BIG_ENDIAN: + return OSTREE_DELTA_ENDIAN_LITTLE; + case G_LITTLE_ENDIAN: + return OSTREE_DELTA_ENDIAN_BIG; + default: + g_assert_not_reached (); + } + } + + return OSTREE_DELTA_ENDIAN_INVALID; + } +} + +gboolean +_ostree_delta_needs_byteswap (GVariant *superblock) +{ + switch (_ostree_delta_get_endianness (superblock, NULL)) + { + case OSTREE_DELTA_ENDIAN_BIG: + return G_BYTE_ORDER == G_LITTLE_ENDIAN; + case OSTREE_DELTA_ENDIAN_LITTLE: + return G_BYTE_ORDER == G_BIG_ENDIAN; + default: + return FALSE; + } +} + +gboolean +_ostree_repo_static_delta_delete (OstreeRepo *self, + const char *delta_id, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *from = NULL; + g_autofree char *to = NULL; + if (!_ostree_parse_delta_name (delta_id, &from, &to, error)) + return FALSE; + + g_autofree char *deltadir = _ostree_get_relative_static_delta_path (from, to, NULL); + struct stat buf; + if (fstatat (self->repo_dir_fd, deltadir, &buf, 0) != 0) + { + if (errno == ENOENT) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Can't find delta %s", delta_id); + return FALSE; + } + else + return glnx_throw_errno_prefix (error, "fstatat(%s)", deltadir); + } + + if (!glnx_shutil_rm_rf_at (self->repo_dir_fd, deltadir, + cancellable, error)) + return FALSE; + + return TRUE; +} + +gboolean +_ostree_repo_static_delta_query_exists (OstreeRepo *self, + const char *delta_id, + gboolean *out_exists, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *from = NULL; + g_autofree char *to = NULL; + if (!_ostree_parse_delta_name (delta_id, &from, &to, error)) + return FALSE; + + g_autofree char *superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to); + if (!glnx_fstatat_allow_noent (self->repo_dir_fd, superblock_path, NULL, 0, error)) + return FALSE; + + *out_exists = (errno == 0); + return TRUE; +} + +gboolean +_ostree_repo_static_delta_dump (OstreeRepo *self, + const char *delta_id, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int superblock_fd = -1; + + if (strchr (delta_id, '/')) + { + if (!glnx_openat_rdonly (AT_FDCWD, delta_id, TRUE, &superblock_fd, error)) + return FALSE; + } + else + { + g_autofree char *from = NULL; + g_autofree char *to = NULL; + if (!_ostree_parse_delta_name (delta_id, &from, &to, error)) + return FALSE; + + g_autofree char *superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to); + if (!glnx_openat_rdonly (self->repo_dir_fd, superblock_path, TRUE, &superblock_fd, error)) + return FALSE; + } + + g_autoptr(GVariant) delta_superblock = NULL; + if (!ot_variant_read_fd (superblock_fd, 0, + (GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT, + TRUE, &delta_superblock, error)) + return FALSE; + + g_print ("Delta: %s\n", delta_id); + g_autoptr(GVariant) from_commit_v = NULL; + g_variant_get_child (delta_superblock, 2, "@ay", &from_commit_v); + g_autofree char *from_commit = NULL; + if (g_variant_n_children (from_commit_v) > 0) + { + if (!ostree_checksum_bytes_peek_validate (from_commit_v, error)) + return FALSE; + from_commit = ostree_checksum_from_bytes_v (from_commit_v); + g_print ("From: %s\n", from_commit); + } + else + { + g_print ("From \n"); + } + g_autoptr(GVariant) to_commit_v = NULL; + g_variant_get_child (delta_superblock, 3, "@ay", &to_commit_v); + if (!ostree_checksum_bytes_peek_validate (to_commit_v, error)) + return FALSE; + g_autofree char *to_commit = ostree_checksum_from_bytes_v (to_commit_v); + g_print ("To: %s\n", to_commit); + + gboolean swap_endian = FALSE; + OstreeDeltaEndianness endianness; + { const char *endianness_description; + gboolean was_heuristic; + + endianness = _ostree_delta_get_endianness (delta_superblock, &was_heuristic); + + switch (endianness) + { + case OSTREE_DELTA_ENDIAN_BIG: + if (was_heuristic) + endianness_description = "big (heuristic)"; + else + endianness_description = "big"; + if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + swap_endian = TRUE; + break; + case OSTREE_DELTA_ENDIAN_LITTLE: + if (was_heuristic) + endianness_description = "little (heuristic)"; + else + endianness_description = "little"; + if (G_BYTE_ORDER == G_BIG_ENDIAN) + swap_endian = TRUE; + break; + case OSTREE_DELTA_ENDIAN_INVALID: + endianness_description = "invalid"; + break; + default: + g_assert_not_reached (); + } + + g_print ("Endianness: %s\n", endianness_description); + } + + guint64 ts; + g_variant_get_child (delta_superblock, 1, "t", &ts); + g_print ("Timestamp: %" G_GUINT64_FORMAT "\n", GUINT64_FROM_BE (ts)); + + g_autoptr(GVariant) recurse = NULL; + g_variant_get_child (delta_superblock, 5, "@ay", &recurse); + g_print ("Number of parents: %u\n", (guint)(g_variant_get_size (recurse) / (OSTREE_SHA256_DIGEST_LEN * 2))); + + g_autoptr(GVariant) fallback = NULL; + g_variant_get_child (delta_superblock, 7, "@a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT, &fallback); + const guint n_fallback = g_variant_n_children (fallback); + + g_print ("Number of fallback entries: %u\n", n_fallback); + + guint64 total_size = 0, total_usize = 0; + guint64 total_fallback_size = 0, total_fallback_usize = 0; + for (guint i = 0; i < n_fallback; i++) + { + guint64 size, usize; + g_autoptr(GVariant) checksum_v = NULL; + char checksum[OSTREE_SHA256_STRING_LEN+1]; + g_variant_get_child (fallback, i, "(y@aytt)", NULL, &checksum_v, &size, &usize); + ostree_checksum_inplace_from_bytes (ostree_checksum_bytes_peek (checksum_v), checksum); + size = maybe_swap_endian_u64 (swap_endian, size); + usize = maybe_swap_endian_u64 (swap_endian, usize); + g_print (" %s\n", checksum); + total_fallback_size += size; + total_fallback_usize += usize; + } + { g_autofree char *sizestr = g_format_size (total_fallback_size); + g_autofree char *usizestr = g_format_size (total_fallback_usize); + g_print ("Total Fallback Size: %" G_GUINT64_FORMAT " (%s)\n", total_fallback_size, sizestr); + g_print ("Total Fallback Uncompressed Size: %" G_GUINT64_FORMAT " (%s)\n", total_fallback_usize, usizestr); + } + + g_autoptr(GVariant) meta_entries = NULL; + guint n_parts; + + g_variant_get_child (delta_superblock, 6, "@a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT, &meta_entries); + n_parts = g_variant_n_children (meta_entries); + g_print ("Number of parts: %u\n", n_parts); + + for (guint i = 0; i < n_parts; i++) + { + if (!show_one_part (self, swap_endian, from_commit, to_commit, meta_entries, i, + &total_size, &total_usize, + cancellable, error)) + return FALSE; + } + + { g_autofree char *sizestr = g_format_size (total_size); + g_autofree char *usizestr = g_format_size (total_usize); + g_print ("Total Part Size: %" G_GUINT64_FORMAT " (%s)\n", total_size, sizestr); + g_print ("Total Part Uncompressed Size: %" G_GUINT64_FORMAT " (%s)\n", total_usize, usizestr); + } + + { guint64 overall_size = total_size + total_fallback_size; + guint64 overall_usize = total_usize + total_fallback_usize; + g_autofree char *sizestr = g_format_size (overall_size); + g_autofree char *usizestr = g_format_size (overall_usize); + g_print ("Total Size: %" G_GUINT64_FORMAT " (%s)\n", overall_size, sizestr); + g_print ("Total Uncompressed Size: %" G_GUINT64_FORMAT " (%s)\n", overall_usize, usizestr); + } + + return TRUE; +} diff --git a/src/libostree/ostree-repo-static-delta-private.h b/src/libostree/ostree-repo-static-delta-private.h new file mode 100644 index 0000000..155acd5 --- /dev/null +++ b/src/libostree/ostree-repo-static-delta-private.h @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-core.h" + +G_BEGIN_DECLS + +/* Arbitrarily chosen */ +#define OSTREE_STATIC_DELTA_PART_MAX_SIZE_BYTES (16*1024*1024) +/* 1 byte for object type, 32 bytes for checksum */ +#define OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN 33 + +#define OSTREE_SUMMARY_STATIC_DELTAS "ostree.static-deltas" + +/** + * OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0: + * + * y compression type (0: none, 'x': lzma) + * --- + * a(uuu) modes + * aa(ayay) xattrs + * ay raw data source + * ay operations + */ +#define OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0 "(a(uuu)aa(ayay)ayay)" + +/** + * OSTREE_STATIC_DELTA_META_ENTRY_FORMAT: + * + * u: version (non-canonical endian) + * ay checksum + * guint64 size: Total size of delta (sum of parts) (non-canonical endian) + * guint64 usize: Uncompressed size of resulting objects on disk (non-canonical endian) + * ARRAY[(guint8 objtype, csum object)] + * + * The checksum is of the delta payload, and each entry in the array + * represents an OSTree object which will be created by the deltapart. + */ + +#define OSTREE_STATIC_DELTA_META_ENTRY_FORMAT "(uayttay)" + + +/** + * OSTREE_STATIC_DELTA_FALLBACK_FORMAT: + * + * y: objtype + * ay: checksum + * t: compressed size (non-canonical endian) + * t: uncompressed size (non-canonical endian) + * + * Object to fetch invididually; includes compressed/uncompressed size. + */ +#define OSTREE_STATIC_DELTA_FALLBACK_FORMAT "(yaytt)" + +/** + * OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT: + * + * A .delta object is a custom binary format. It has the following high + * level form: + * + * delta-descriptor: + * metadata: a{sv} + * t: timestamp (big endian) + * from: ay checksum + * to: ay checksum + * commit: new commit object + * ARRAY[(csum from, csum to)]: ay + * ARRAY[delta-meta-entry] + * array[fallback] + * + * The metadata would include things like a version number, as well as + * extended verification data like a GPG signature. + * + * The second array is an array of delta objects that should be + * fetched and applied before this one. This is a fairly generic + * recursion mechanism that would potentially allow saving significant + * storage space on the server. + * + * The heart of the static delta: the array of delta parts. + * + * Finally, we have the fallback array, which is the set of objects to + * fetch individually - the compiler determined it wasn't worth + * duplicating the space. + */ +#define OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT "(a{sv}tayay" OSTREE_COMMIT_GVARIANT_STRING "aya" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT "a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT ")" + +typedef enum { + OSTREE_STATIC_DELTA_OPEN_FLAGS_NONE = 0, + OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM = (1 << 0), + OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED = (1 << 1) +} OstreeStaticDeltaOpenFlags; + +typedef enum { + OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE = 'S', + OSTREE_STATIC_DELTA_OP_OPEN = 'o', + OSTREE_STATIC_DELTA_OP_WRITE = 'w', + OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE = 'r', + OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE = 'R', + OSTREE_STATIC_DELTA_OP_CLOSE = 'c', + OSTREE_STATIC_DELTA_OP_BSPATCH = 'B' +} OstreeStaticDeltaOpCode; +#define OSTREE_STATIC_DELTA_N_OPS 7 + +gboolean +_ostree_static_delta_part_open (GInputStream *part_in, + GBytes *inline_part_bytes, + OstreeStaticDeltaOpenFlags flags, + const char *expected_checksum, + GVariant **out_part, + GCancellable *cancellable, + GError **error); + +typedef struct { + guint n_ops_executed[OSTREE_STATIC_DELTA_N_OPS]; +} OstreeDeltaExecuteStats; + +gboolean _ostree_static_delta_part_execute (OstreeRepo *repo, + GVariant *header, + GVariant *part_payload, + gboolean stats_only, + OstreeDeltaExecuteStats *stats, + GCancellable *cancellable, + GError **error); + +void _ostree_static_delta_part_execute_async (OstreeRepo *repo, + GVariant *header, + GVariant *part_payload, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean _ostree_static_delta_part_execute_finish (OstreeRepo *repo, + GAsyncResult *result, + GError **error); + +gboolean +_ostree_static_delta_parse_checksum_array (GVariant *array, + guint8 **out_checksums_array, + guint *out_n_checksums, + GError **error); + +gboolean +_ostree_repo_static_delta_part_have_all_objects (OstreeRepo *repo, + GVariant *checksum_array, + gboolean *out_have_all, + GCancellable *cancellable, + GError **error); + +typedef struct { + char *checksum; + guint64 size; + GPtrArray *basenames; +} OstreeDeltaContentSizeNames; + +void _ostree_delta_content_sizenames_free (gpointer v); + +gboolean +_ostree_delta_compute_similar_objects (OstreeRepo *repo, + GVariant *from_commit, + GVariant *to_commit, + GHashTable *new_reachable_regfile_content, + guint similarity_percent_threshold, + GHashTable **out_modified_regfile_content, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_static_delta_query_exists (OstreeRepo *repo, + const char *delta_id, + gboolean *out_exists, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_static_delta_dump (OstreeRepo *repo, + const char *delta_id, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_repo_static_delta_delete (OstreeRepo *repo, + const char *delta_id, + GCancellable *cancellable, + GError **error); + +/* Used for static deltas which due to a historical mistake are + * inconsistent endian. + * + * https://bugzilla.gnome.org/show_bug.cgi?id=762515 + */ +static inline guint32 +maybe_swap_endian_u32 (gboolean swap, + guint32 v) +{ + if (!swap) + return v; + return GUINT32_SWAP_LE_BE (v); +} + +static inline guint64 +maybe_swap_endian_u64 (gboolean swap, + guint64 v) +{ + if (!swap) + return v; + return GUINT64_SWAP_LE_BE (v); +} + +typedef enum { + OSTREE_DELTA_ENDIAN_BIG, + OSTREE_DELTA_ENDIAN_LITTLE, + OSTREE_DELTA_ENDIAN_INVALID +} OstreeDeltaEndianness; + +OstreeDeltaEndianness _ostree_delta_get_endianness (GVariant *superblock, gboolean *out_was_heuristic); + +gboolean _ostree_delta_needs_byteswap (GVariant *superblock); + +G_END_DECLS diff --git a/src/libostree/ostree-repo-static-delta-processing.c b/src/libostree/ostree-repo-static-delta-processing.c new file mode 100644 index 0000000..7b5b9eb --- /dev/null +++ b/src/libostree/ostree-repo-static-delta-processing.c @@ -0,0 +1,802 @@ +/* + * Copyright (C) 2013,2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include +#include +#include + +#include "ostree-core-private.h" +#include "ostree-repo-private.h" +#include "ostree-repo-static-delta-private.h" +#include "ostree-lzma-decompressor.h" +#include "otutil.h" +#include "ostree-varint.h" +#include "bsdiff/bspatch.h" + +/* This should really always be true, but hey, let's just assert it */ +G_STATIC_ASSERT (sizeof (guint) >= sizeof (guint32)); + +typedef struct { + gboolean stats_only; + OstreeRepo *repo; + guint checksum_index; + const guint8 *checksums; + guint n_checksums; + + const guint8 *opdata; + guint oplen; + + GVariant *mode_dict; + GVariant *xattr_dict; + + gboolean object_start; + gboolean caught_error; + GError **async_error; + + OstreeObjectType output_objtype; + guint64 content_size; + char checksum[OSTREE_SHA256_STRING_LEN+1]; + OstreeRepoBareContent content_out; + char *read_source_object; + int read_source_fd; + gboolean have_obj; + guint32 uid; + guint32 gid; + guint32 mode; + GVariant *xattrs; + + const guint8 *output_target; + const guint8 *input_target_csum; + + const guint8 *payload_data; + guint64 payload_size; +} StaticDeltaExecutionState; + +typedef struct { + StaticDeltaExecutionState *state; + char checksum[OSTREE_SHA256_STRING_LEN+1]; +} StaticDeltaContentWrite; + +typedef gboolean (*DispatchOpFunc) (OstreeRepo *repo, + StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error); + +#define OPPROTO(name) \ + static gboolean dispatch_##name (OstreeRepo *repo, \ + StaticDeltaExecutionState *state, \ + GCancellable *cancellable, \ + GError **error); + +OPPROTO(open_splice_and_close) +OPPROTO(open) +OPPROTO(write) +OPPROTO(set_read_source) +OPPROTO(unset_read_source) +OPPROTO(close) +OPPROTO(bspatch) +#undef OPPROTO + +static void +static_delta_execution_state_init (StaticDeltaExecutionState *state) +{ + state->read_source_fd = -1; +} + +static gboolean +read_varuint64 (StaticDeltaExecutionState *state, + guint64 *out_value, + GError **error) +{ + gsize bytes_read; + if (!_ostree_read_varuint64 (state->opdata, state->oplen, out_value, &bytes_read)) + { + return glnx_throw (error, "%s", "Unexpected EOF reading varint"); + } + state->opdata += bytes_read; + state->oplen -= bytes_read; + return TRUE; +} + +static gboolean +open_output_target (StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error) +{ + g_assert (state->checksums != NULL); + g_assert (state->output_target == NULL); + g_assert (state->checksum_index < state->n_checksums); + + guint8 *objcsum = (guint8*)state->checksums + (state->checksum_index * OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN); + + if (G_UNLIKELY(!ostree_validate_structureof_objtype (*objcsum, error))) + return FALSE; + + state->output_objtype = (OstreeObjectType) *objcsum; + state->output_target = objcsum + 1; + + ostree_checksum_inplace_from_bytes (state->output_target, state->checksum); + + return TRUE; +} + +static guint +delta_opcode_index (OstreeStaticDeltaOpCode op) +{ + switch (op) + { + case OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE: + return 0; + case OSTREE_STATIC_DELTA_OP_OPEN: + return 1; + case OSTREE_STATIC_DELTA_OP_WRITE: + return 2; + case OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE: + return 3; + case OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE: + return 4; + case OSTREE_STATIC_DELTA_OP_CLOSE: + return 5; + case OSTREE_STATIC_DELTA_OP_BSPATCH: + return 6; + default: + g_assert_not_reached (); + } +} + +gboolean +_ostree_static_delta_part_execute (OstreeRepo *repo, + GVariant *objects, + GVariant *part, + gboolean stats_only, + OstreeDeltaExecuteStats *stats, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + guint8 *checksums_data; + g_autoptr(GVariant) mode_dict = NULL; + g_autoptr(GVariant) xattr_dict = NULL; + g_autoptr(GVariant) payload = NULL; + g_autoptr(GVariant) ops = NULL; + StaticDeltaExecutionState statedata = { 0, }; + StaticDeltaExecutionState *state = &statedata; + guint n_executed = 0; + + static_delta_execution_state_init (&statedata); + + state->repo = repo; + state->async_error = error; + state->stats_only = stats_only; + + if (!_ostree_static_delta_parse_checksum_array (objects, + &checksums_data, + &state->n_checksums, + error)) + goto out; + + /* Skip processing for empty delta part */ + if (state->n_checksums == 0) + { + ret = TRUE; + goto out; + } + + state->checksums = checksums_data; + + g_variant_get (part, "(@a(uuu)@aa(ayay)@ay@ay)", + &mode_dict, + &xattr_dict, + &payload, &ops); + + state->mode_dict = mode_dict; + state->xattr_dict = xattr_dict; + + state->payload_data = g_variant_get_data (payload); + state->payload_size = g_variant_get_size (payload); + + state->oplen = g_variant_n_children (ops); + state->opdata = g_variant_get_data (ops); + + while (state->oplen > 0) + { + guint8 opcode; + + opcode = state->opdata[0]; + state->oplen--; + state->opdata++; + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + goto out; + + switch (opcode) + { + case OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE: + if (!dispatch_open_splice_and_close (repo, state, cancellable, error)) + goto out; + break; + case OSTREE_STATIC_DELTA_OP_OPEN: + if (!dispatch_open (repo, state, cancellable, error)) + goto out; + break; + case OSTREE_STATIC_DELTA_OP_WRITE: + if (!dispatch_write (repo, state, cancellable, error)) + goto out; + break; + case OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE: + if (!dispatch_set_read_source (repo, state, cancellable, error)) + goto out; + break; + case OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE: + if (!dispatch_unset_read_source (repo, state, cancellable, error)) + goto out; + break; + case OSTREE_STATIC_DELTA_OP_CLOSE: + if (!dispatch_close (repo, state, cancellable, error)) + goto out; + break; + case OSTREE_STATIC_DELTA_OP_BSPATCH: + if (!dispatch_bspatch (repo, state, cancellable, error)) + goto out; + break; + default: + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + "Unknown opcode %u at offset %u", opcode, n_executed); + goto out; + } + + n_executed++; + if (stats) + stats->n_ops_executed[delta_opcode_index(opcode)]++; + } + + if (state->caught_error) + goto out; + + ret = TRUE; + out: + _ostree_repo_bare_content_cleanup (&state->content_out); + return ret; +} + +typedef struct { + OstreeRepo *repo; + GVariant *header; + GVariant *part; + GCancellable *cancellable; + GSimpleAsyncResult *result; +} StaticDeltaPartExecuteAsyncData; + +static void +static_delta_part_execute_async_data_free (gpointer user_data) +{ + StaticDeltaPartExecuteAsyncData *data = user_data; + + g_clear_object (&data->repo); + g_variant_unref (data->header); + g_variant_unref (data->part); + g_clear_object (&data->cancellable); + g_free (data); +} + +static void +static_delta_part_execute_thread (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + GError *error = NULL; + StaticDeltaPartExecuteAsyncData *data; + + data = g_simple_async_result_get_op_res_gpointer (res); + if (!_ostree_static_delta_part_execute (data->repo, + data->header, + data->part, + FALSE, NULL, + cancellable, &error)) + g_simple_async_result_take_error (res, error); +} + +void +_ostree_static_delta_part_execute_async (OstreeRepo *repo, + GVariant *header, + GVariant *part, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + StaticDeltaPartExecuteAsyncData *asyncdata; + + asyncdata = g_new0 (StaticDeltaPartExecuteAsyncData, 1); + asyncdata->repo = g_object_ref (repo); + asyncdata->header = g_variant_ref (header); + asyncdata->part = g_variant_ref (part); + asyncdata->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + asyncdata->result = g_simple_async_result_new ((GObject*) repo, + callback, user_data, + _ostree_static_delta_part_execute_async); + + g_simple_async_result_set_op_res_gpointer (asyncdata->result, asyncdata, + static_delta_part_execute_async_data_free); + g_simple_async_result_run_in_thread (asyncdata->result, static_delta_part_execute_thread, G_PRIORITY_DEFAULT, cancellable); + g_object_unref (asyncdata->result); +} + +gboolean +_ostree_static_delta_part_execute_finish (OstreeRepo *repo, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == _ostree_static_delta_part_execute_async); + + if (g_simple_async_result_propagate_error (simple, error)) + return FALSE; + return TRUE; +} + +static gboolean +validate_ofs (StaticDeltaExecutionState *state, + guint64 offset, + guint64 length, + GError **error) +{ + if (G_UNLIKELY (offset + length < offset || + offset + length > state->payload_size)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + "Invalid offset/length %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, + offset, length); + return FALSE; + } + return TRUE; +} + +static gboolean +do_content_open_generic (OstreeRepo *repo, + StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error) +{ + guint64 mode_offset; + guint64 xattr_offset; + + if (!read_varuint64 (state, &mode_offset, error)) + return FALSE; + if (!read_varuint64 (state, &xattr_offset, error)) + return FALSE; + + g_autoptr(GVariant) modev = g_variant_get_child_value (state->mode_dict, mode_offset); + guint32 uid, gid, mode; + g_variant_get (modev, "(uuu)", &uid, &gid, &mode); + state->uid = GUINT32_FROM_BE (uid); + state->gid = GUINT32_FROM_BE (gid); + state->mode = GUINT32_FROM_BE (mode); + + state->xattrs = g_variant_get_child_value (state->xattr_dict, xattr_offset); + + return TRUE; +} + +struct bzpatch_opaque_s +{ + StaticDeltaExecutionState *state; + guint64 offset, length; +}; + +static int +bspatch_read (const struct bspatch_stream* stream, void* buffer, int length) +{ + struct bzpatch_opaque_s *opaque = stream->opaque; + + g_assert (length <= opaque->length); + g_assert (opaque->offset + length <= opaque->state->payload_size); + + memcpy (buffer, opaque->state->payload_data + opaque->offset, length); + opaque->offset += length; + opaque->length -= length; + return 0; +} + +static gboolean +dispatch_bspatch (OstreeRepo *repo, + StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error) +{ + guint64 offset, length; + + if (!read_varuint64 (state, &offset, error)) + return FALSE; + if (!read_varuint64 (state, &length, error)) + return FALSE; + + if (state->stats_only) + return TRUE; /* Early return */ + + if (!state->have_obj) + { + g_autoptr(GMappedFile) input_mfile = g_mapped_file_new_from_fd (state->read_source_fd, FALSE, error); + if (!input_mfile) + return FALSE; + + g_autofree guchar *buf = g_malloc0 (state->content_size); + + struct bzpatch_opaque_s opaque; + opaque.state = state; + opaque.offset = offset; + opaque.length = length; + struct bspatch_stream stream; + stream.read = bspatch_read; + stream.opaque = &opaque; + if (bspatch ((const guint8*)g_mapped_file_get_contents (input_mfile), + g_mapped_file_get_length (input_mfile), + buf, + state->content_size, + &stream) < 0) + return FALSE; + + if (!_ostree_repo_bare_content_write (repo, &state->content_out, + buf, state->content_size, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +dispatch_open_splice_and_close (OstreeRepo *repo, + StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + + if (!open_output_target (state, cancellable, error)) + goto out; + + if (OSTREE_OBJECT_TYPE_IS_META (state->output_objtype)) + { + g_autoptr(GVariant) metadata = NULL; + guint64 offset; + guint64 length; + + if (!read_varuint64 (state, &length, error)) + goto out; + if (!read_varuint64 (state, &offset, error)) + goto out; + if (!validate_ofs (state, offset, length, error)) + goto out; + + if (state->stats_only) + { + ret = TRUE; + goto out; + } + + /* Unfortunately we need a copy because GVariant wants pointer-alignment + * and we didn't guarantee that in static deltas. We can do so in the + * future. + */ + g_autoptr(GBytes) metadata_copy = g_bytes_new (state->payload_data + offset, length); + metadata = g_variant_new_from_bytes (ostree_metadata_variant_type (state->output_objtype), + metadata_copy, FALSE); + + { + g_autofree guchar *actual_csum = NULL; + + if (!ostree_repo_write_metadata (state->repo, state->output_objtype, + state->checksum, + metadata, &actual_csum, + cancellable, + error)) + goto out; + } + } + else + { + guint64 content_offset; + guint64 objlen; + g_autoptr(GInputStream) object_input = NULL; + g_autoptr(GInputStream) memin = NULL; + + if (!do_content_open_generic (repo, state, cancellable, error)) + goto out; + + if (!read_varuint64 (state, &state->content_size, error)) + goto out; + if (!read_varuint64 (state, &content_offset, error)) + goto out; + if (!validate_ofs (state, content_offset, state->content_size, error)) + goto out; + + if (state->stats_only) + { + ret = TRUE; + goto out; + } + + /* Fast path for regular files to bare repositories */ + if (S_ISREG (state->mode) && + _ostree_repo_mode_is_bare (repo->mode)) + { + if (!ostree_repo_has_object (repo, OSTREE_OBJECT_TYPE_FILE, state->checksum, + &state->have_obj, cancellable, error)) + goto out; + + if (!state->have_obj) + { + if (!_ostree_repo_bare_content_open (repo, state->checksum, + state->content_size, + state->uid, state->gid, state->mode, + state->xattrs, + &state->content_out, + cancellable, error)) + goto out; + + if (!_ostree_repo_bare_content_write (repo, &state->content_out, + state->payload_data + content_offset, + state->content_size, + cancellable, error)) + goto out; + } + } + else + { + /* Slower path, for symlinks and unpacking deltas into archive */ + g_autoptr(GFileInfo) finfo = + _ostree_mode_uidgid_to_gfileinfo (state->mode, state->uid, state->gid); + + if (S_ISLNK (state->mode)) + { + g_autofree char *nulterminated_target = + g_strndup ((char*)state->payload_data + content_offset, state->content_size); + g_file_info_set_symlink_target (finfo, nulterminated_target); + } + else + { + g_assert (S_ISREG (state->mode)); + g_file_info_set_size (finfo, state->content_size); + memin = g_memory_input_stream_new_from_data (state->payload_data + content_offset, state->content_size, NULL); + } + + if (!ostree_raw_file_to_content_stream (memin, finfo, state->xattrs, + &object_input, &objlen, + cancellable, error)) + goto out; + + { + g_autofree guchar *actual_csum = NULL; + if (!ostree_repo_write_content (state->repo, + state->checksum, + object_input, + objlen, + &actual_csum, + cancellable, + error)) + goto out; + } + } + } + + if (!dispatch_close (repo, state, cancellable, error)) + goto out; + + ret = TRUE; + out: + if (state->stats_only) + (void) dispatch_close (repo, state, cancellable, NULL); + if (!ret) + g_prefix_error (error, "opcode open-splice-and-close: "); + return ret; +} + +static gboolean +dispatch_open (OstreeRepo *repo, + StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("opcode open", error); + + g_assert (state->output_target == NULL); + /* FIXME - lift this restriction */ + if (!state->stats_only) + { + g_assert (repo->mode == OSTREE_REPO_MODE_BARE || + repo->mode == OSTREE_REPO_MODE_BARE_USER || + repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY); + } + + if (!open_output_target (state, cancellable, error)) + return FALSE; + + if (!do_content_open_generic (repo, state, cancellable, error)) + return FALSE; + + if (!read_varuint64 (state, &state->content_size, error)) + return FALSE; + + if (state->stats_only) + return TRUE; /* Early return */ + + if (!ostree_repo_has_object (repo, OSTREE_OBJECT_TYPE_FILE, state->checksum, + &state->have_obj, cancellable, error)) + return FALSE; + + if (!state->have_obj) + { + if (!_ostree_repo_bare_content_open (repo, state->checksum, + state->content_size, + state->uid, state->gid, state->mode, + state->xattrs, + &state->content_out, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +dispatch_write (OstreeRepo *repo, + StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("opcode write", error); + guint64 content_size; + guint64 content_offset; + + if (!read_varuint64 (state, &content_size, error)) + return FALSE; + if (!read_varuint64 (state, &content_offset, error)) + return FALSE; + + if (state->stats_only) + return TRUE; /* Early return */ + + if (!state->have_obj) + { + if (state->read_source_fd != -1) + { + while (content_size > 0) + { + char buf[4096]; + gssize bytes_read; + + do + bytes_read = pread (state->read_source_fd, buf, MIN(sizeof(buf), content_size), content_offset); + while (G_UNLIKELY (bytes_read == -1 && errno == EINTR)); + if (bytes_read == -1) + return glnx_throw_errno_prefix (error, "read"); + if (G_UNLIKELY (bytes_read == 0)) + return glnx_throw (error, "Unexpected EOF reading object %s", state->read_source_object); + + if (!_ostree_repo_bare_content_write (repo, &state->content_out, + (guint8*)buf, bytes_read, + cancellable, error)) + return FALSE; + + content_size -= bytes_read; + content_offset += bytes_read; + } + } + else + { + if (!validate_ofs (state, content_offset, content_size, error)) + return FALSE; + + if (!_ostree_repo_bare_content_write (repo, &state->content_out, + state->payload_data + content_offset, content_size, + cancellable, error)) + return FALSE; + } + } + + return TRUE; +} + +static gboolean +dispatch_set_read_source (OstreeRepo *repo, + StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("opcode set-read-source", error); + guint64 source_offset; + + glnx_close_fd (&state->read_source_fd); + + if (!read_varuint64 (state, &source_offset, error)) + return FALSE; + if (!validate_ofs (state, source_offset, 32, error)) + return FALSE; + + if (state->stats_only) + return TRUE; /* Early return */ + + g_free (state->read_source_object); + state->read_source_object = ostree_checksum_from_bytes (state->payload_data + source_offset); + + if (!_ostree_repo_load_file_bare (repo, state->read_source_object, + &state->read_source_fd, + NULL, NULL, NULL, + cancellable, error)) + return FALSE; + + return TRUE; +} + +static gboolean +dispatch_unset_read_source (OstreeRepo *repo, + StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("opcode unset-read-source", error); + + if (state->stats_only) + return TRUE; /* Early return */ + + glnx_close_fd (&state->read_source_fd); + g_clear_pointer (&state->read_source_object, g_free); + + return TRUE; +} + +static gboolean +dispatch_close (OstreeRepo *repo, + StaticDeltaExecutionState *state, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR("opcode close", error); + + if (state->content_out.initialized) + { + char actual_checksum[OSTREE_SHA256_STRING_LEN+1]; + if (!_ostree_repo_bare_content_commit (repo, &state->content_out, actual_checksum, + sizeof (actual_checksum), + cancellable, error)) + return FALSE; + + g_assert_cmpstr (state->checksum, ==, actual_checksum); + } + + if (!dispatch_unset_read_source (repo, state, cancellable, error)) + return FALSE; + + g_clear_pointer (&state->xattrs, g_variant_unref); + _ostree_repo_bare_content_cleanup (&state->content_out); + + state->checksum_index++; + state->output_target = NULL; + + return TRUE; +} diff --git a/src/libostree/ostree-repo-traverse.c b/src/libostree/ostree-repo-traverse.c new file mode 100644 index 0000000..d0edd65 --- /dev/null +++ b/src/libostree/ostree-repo-traverse.c @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "libglnx.h" +#include "ostree.h" +#include "otutil.h" + +struct _OstreeRepoRealCommitTraverseIter { + gboolean initialized; + OstreeRepo *repo; + GVariant *commit; + GVariant *current_dir; + const char *name; + OstreeRepoCommitIterResult state; + guint idx; + char checksum_content[OSTREE_SHA256_STRING_LEN+1]; + char checksum_meta[OSTREE_SHA256_STRING_LEN+1]; +}; + +/** + * ostree_repo_commit_traverse_iter_init_commit: + * @iter: An iter + * @repo: A repo + * @commit: Variant of type %OSTREE_OBJECT_TYPE_COMMIT + * @flags: Flags + * @error: Error + * + * Initialize (in place) an iterator over the root of a commit object. + */ +gboolean +ostree_repo_commit_traverse_iter_init_commit (OstreeRepoCommitTraverseIter *iter, + OstreeRepo *repo, + GVariant *commit, + OstreeRepoCommitTraverseFlags flags, + GError **error) +{ + struct _OstreeRepoRealCommitTraverseIter *real = + (struct _OstreeRepoRealCommitTraverseIter*)iter; + + memset (real, 0, sizeof (*real)); + real->initialized = TRUE; + real->repo = g_object_ref (repo); + real->commit = g_variant_ref (commit); + real->current_dir = NULL; + real->idx = 0; + + g_autoptr(GVariant) content_csum_bytes = NULL; + g_variant_get_child (commit, 6, "@ay", &content_csum_bytes); + const guchar *csum = ostree_checksum_bytes_peek_validate (content_csum_bytes, error); + if (!csum) + return FALSE; + ostree_checksum_inplace_from_bytes (csum, real->checksum_content); + + g_autoptr(GVariant) meta_csum_bytes = NULL; + g_variant_get_child (commit, 7, "@ay", &meta_csum_bytes); + csum = ostree_checksum_bytes_peek_validate (meta_csum_bytes, error); + if (!csum) + return FALSE; + ostree_checksum_inplace_from_bytes (csum, real->checksum_meta); + + return TRUE; +} + +/** + * ostree_repo_commit_traverse_iter_init_dirtree: + * @iter: An iter + * @repo: A repo + * @dirtree: Variant of type %OSTREE_OBJECT_TYPE_DIR_TREE + * @flags: Flags + * @error: Error + * + * Initialize (in place) an iterator over a directory tree. + */ +gboolean +ostree_repo_commit_traverse_iter_init_dirtree (OstreeRepoCommitTraverseIter *iter, + OstreeRepo *repo, + GVariant *dirtree, + OstreeRepoCommitTraverseFlags flags, + GError **error) +{ + struct _OstreeRepoRealCommitTraverseIter *real = + (struct _OstreeRepoRealCommitTraverseIter*)iter; + + memset (real, 0, sizeof (*real)); + real->initialized = TRUE; + real->repo = g_object_ref (repo); + real->current_dir = g_variant_ref (dirtree); + real->idx = 0; + + return TRUE; +} + +/** + * ostree_repo_commit_traverse_iter_next: + * @iter: An iter + * @cancellable: Cancellable + * @error: Error + * + * Step the interator to the next item. Files will be returned first, + * then subdirectories. Call this in a loop; upon encountering + * %OSTREE_REPO_COMMIT_ITER_RESULT_END, there will be no more files or + * directories. If %OSTREE_REPO_COMMIT_ITER_RESULT_DIR is returned, + * then call ostree_repo_commit_traverse_iter_get_dir() to retrieve + * data for that directory. Similarly, if + * %OSTREE_REPO_COMMIT_ITER_RESULT_FILE is returned, call + * ostree_repo_commit_traverse_iter_get_file(). + * + * If %OSTREE_REPO_COMMIT_ITER_RESULT_ERROR is returned, it is a + * program error to call any further API on @iter except for + * ostree_repo_commit_traverse_iter_clear(). + */ +OstreeRepoCommitIterResult +ostree_repo_commit_traverse_iter_next (OstreeRepoCommitTraverseIter *iter, + GCancellable *cancellable, + GError **error) +{ + struct _OstreeRepoRealCommitTraverseIter *real = + (struct _OstreeRepoRealCommitTraverseIter*)iter; + OstreeRepoCommitIterResult res = OSTREE_REPO_COMMIT_ITER_RESULT_ERROR; + + if (!real->current_dir) + { + if (!ostree_repo_load_variant (real->repo, OSTREE_OBJECT_TYPE_DIR_TREE, + real->checksum_content, + &real->current_dir, + error)) + goto out; + res = OSTREE_REPO_COMMIT_ITER_RESULT_DIR; + } + else + { + guint nfiles; + guint ndirs; + guint idx; + const guchar *csum; + g_autoptr(GVariant) content_csum_v = NULL; + g_autoptr(GVariant) meta_csum_v = NULL; + g_autoptr(GVariant) files_variant = NULL; + g_autoptr(GVariant) dirs_variant = NULL; + + files_variant = g_variant_get_child_value (real->current_dir, 0); + dirs_variant = g_variant_get_child_value (real->current_dir, 1); + + nfiles = g_variant_n_children (files_variant); + ndirs = g_variant_n_children (dirs_variant); + if (real->idx < nfiles) + { + idx = real->idx; + g_variant_get_child (files_variant, idx, "(&s@ay)", + &real->name, + &content_csum_v); + + csum = ostree_checksum_bytes_peek_validate (content_csum_v, error); + if (!csum) + goto out; + ostree_checksum_inplace_from_bytes (csum, real->checksum_content); + + res = OSTREE_REPO_COMMIT_ITER_RESULT_FILE; + + real->idx++; + } + else if (real->idx < nfiles + ndirs) + { + idx = real->idx - nfiles; + + g_variant_get_child (dirs_variant, idx, "(&s@ay@ay)", + &real->name, &content_csum_v, &meta_csum_v); + + csum = ostree_checksum_bytes_peek_validate (content_csum_v, error); + if (!csum) + goto out; + ostree_checksum_inplace_from_bytes (csum, real->checksum_content); + + csum = ostree_checksum_bytes_peek_validate (meta_csum_v, error); + if (!csum) + goto out; + ostree_checksum_inplace_from_bytes (csum, real->checksum_meta); + + res = OSTREE_REPO_COMMIT_ITER_RESULT_DIR; + + real->idx++; + } + else + res = OSTREE_REPO_COMMIT_ITER_RESULT_END; + } + + real->state = res; + out: + return res; +} + +/** + * ostree_repo_commit_traverse_iter_get_file: + * @iter: An iter + * @out_name: (out) (transfer none): Name of current file + * @out_checksum: (out) (transfer none): Checksum of current file + * + * Return information on the current file. This function may only be + * called if %OSTREE_REPO_COMMIT_ITER_RESULT_FILE was returned from + * ostree_repo_commit_traverse_iter_next(). + */ +void +ostree_repo_commit_traverse_iter_get_file (OstreeRepoCommitTraverseIter *iter, + char **out_name, + char **out_checksum) +{ + struct _OstreeRepoRealCommitTraverseIter *real = + (struct _OstreeRepoRealCommitTraverseIter*)iter; + *out_name = (char*)real->name; + *out_checksum = (char*)real->checksum_content; +} + +/** + * ostree_repo_commit_traverse_iter_get_dir: + * @iter: An iter + * @out_name: (out) (transfer none): Name of current dir + * @out_content_checksum: (out) (transfer none): Checksum of current content + * @out_meta_checksum: (out) (transfer none): Checksum of current metadata + * + * Return information on the current directory. This function may + * only be called if %OSTREE_REPO_COMMIT_ITER_RESULT_DIR was returned + * from ostree_repo_commit_traverse_iter_next(). + */ +void +ostree_repo_commit_traverse_iter_get_dir (OstreeRepoCommitTraverseIter *iter, + char **out_name, + char **out_content_checksum, + char **out_meta_checksum) +{ + struct _OstreeRepoRealCommitTraverseIter *real = + (struct _OstreeRepoRealCommitTraverseIter*)iter; + *out_name = (char*)real->name; + *out_content_checksum = (char*)real->checksum_content; + *out_meta_checksum = (char*)real->checksum_meta; +} + +void +ostree_repo_commit_traverse_iter_clear (OstreeRepoCommitTraverseIter *iter) +{ + struct _OstreeRepoRealCommitTraverseIter *real = + (struct _OstreeRepoRealCommitTraverseIter*)iter; + g_clear_object (&real->repo); + g_clear_pointer (&real->commit, g_variant_unref); + g_clear_pointer (&real->current_dir, g_variant_unref); +} + +void +ostree_repo_commit_traverse_iter_cleanup (void *p) +{ + OstreeRepoCommitTraverseIter *iter = p; + struct _OstreeRepoRealCommitTraverseIter *real = + (struct _OstreeRepoRealCommitTraverseIter*)iter; + if (real->initialized) + { + ostree_repo_commit_traverse_iter_clear (iter); + real->initialized = FALSE; + } +} + +/** + * ostree_repo_traverse_new_reachable: + * + * This hash table is a set of #GVariant which can be accessed via + * ostree_object_name_deserialize(). + * + * Returns: (transfer container) (element-type GVariant GVariant): A new hash table + */ +GHashTable * +ostree_repo_traverse_new_reachable (void) +{ + return g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, + NULL, (GDestroyNotify)g_variant_unref); +} + +/** + * ostree_repo_traverse_new_parents: + * + * This hash table is a mapping from #GVariant which can be accessed + * via ostree_object_name_deserialize() to a #GVariant containing either + * a similar #GVariant or and array of them, listing the parents of the key. + * + * Returns: (transfer container) (element-type GVariant GVariant): A new hash table + * + * Since: 2018.5 + */ +GHashTable * +ostree_repo_traverse_new_parents (void) +{ + return g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, + (GDestroyNotify)g_variant_unref, (GDestroyNotify)g_variant_unref); +} + +static void +parents_get_commits (GHashTable *parents_ht, GVariant *object, GHashTable *res) +{ + const char *checksum; + OstreeObjectType type; + + if (object == NULL) + return; + + ostree_object_name_deserialize (object, &checksum, &type); + if (type == OSTREE_OBJECT_TYPE_COMMIT) + g_hash_table_add (res, g_strdup (checksum)); + else + { + GVariant *parents = g_hash_table_lookup (parents_ht, object); + + if (parents == NULL) + g_debug ("Unexpected NULL parent"); + else if (g_variant_is_of_type (parents, G_VARIANT_TYPE_ARRAY)) + { + gsize i, len = g_variant_n_children (parents); + + for (i = 0; i < len; i++) + { + g_autoptr(GVariant) parent = g_variant_get_child_value (parents, i); + parents_get_commits (parents_ht, parent, res); + } + } + else + parents_get_commits (parents_ht, parents, res); + } +} + +/** + * ostree_repo_traverse_parents_get_commits: + * + * Gets all the commits that a certain object belongs to, as recorded + * by a parents table gotten from ostree_repo_traverse_commit_union_with_parents. + * + * Returns: (transfer full) (array zero-terminated=1): An array of checksums for + * the commits the key belongs to. + * + * Since: 2018.5 + */ +char ** +ostree_repo_traverse_parents_get_commits (GHashTable *parents, GVariant *object) +{ + g_autoptr(GHashTable) res = g_hash_table_new (g_str_hash, g_str_equal); + + parents_get_commits (parents, object, res); + + return (char **)g_hash_table_get_keys_as_array (res, NULL); +} + +static gboolean +traverse_dirtree (OstreeRepo *repo, + const char *checksum, + GVariant *parent_key, + GHashTable *inout_reachable, + GHashTable *inout_parents, + gboolean ignore_missing_dirs, + GCancellable *cancellable, + GError **error); + +static void +add_parent_ref (GHashTable *inout_parents, + GVariant *key, + GVariant *parent_key) +{ + GVariant *old_parents; + + if (inout_parents == NULL) + return; + + old_parents = g_hash_table_lookup (inout_parents, key); + if (old_parents == NULL) + { + /* For the common case of a single pointer we skip using an array to save memory. */ + g_hash_table_insert (inout_parents, g_variant_ref (key), g_variant_ref (parent_key)); + } + else + { + g_autofree GVariant **new_parents = NULL; + gsize i, len = 0; + + if (g_variant_is_of_type (old_parents, G_VARIANT_TYPE_ARRAY)) + { + gsize old_parents_len = g_variant_n_children (old_parents); + new_parents = g_new (GVariant *, old_parents_len + 1); + for (i = 0; i < old_parents_len ; i++) + { + g_autoptr(GVariant) old_parent = g_variant_get_child_value (old_parents, i); + if (!g_variant_equal (old_parent, parent_key)) + new_parents[len++] = g_steal_pointer (&old_parent); + } + } + else + { + new_parents = g_new (GVariant *, 2); + if (!g_variant_equal (old_parents, parent_key)) + new_parents[len++] = g_variant_ref (old_parents); + } + new_parents[len++] = g_variant_ref (parent_key); + g_hash_table_insert (inout_parents, g_variant_ref (key), + g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(su)"), new_parents , len))); + for (i = 0; i < len; i++) + g_variant_unref (new_parents[i]); + } +} + + +static gboolean +traverse_iter (OstreeRepo *repo, + OstreeRepoCommitTraverseIter *iter, + GVariant *parent_key, + GHashTable *inout_reachable, + GHashTable *inout_parents, + gboolean ignore_missing_dirs, + GCancellable *cancellable, + GError **error) +{ + while (TRUE) + { + g_autoptr(GVariant) key = NULL; + g_autoptr(GError) local_error = NULL; + OstreeRepoCommitIterResult iterres = + ostree_repo_commit_traverse_iter_next (iter, cancellable, &local_error); + + if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_ERROR) + { + /* There is only one kind of not-found error, which is + failing to load the dirmeta itself, if so, we ignore that + (and the whole subtree) if told to. */ + if (ignore_missing_dirs && + g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_debug ("Ignoring not-found dirmeta"); + return TRUE; /* Note early return */ + } + + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_END) + break; + else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_FILE) + { + char *name; + char *checksum; + + ostree_repo_commit_traverse_iter_get_file (iter, &name, &checksum); + + g_debug ("Found file object %s", checksum); + key = g_variant_ref_sink (ostree_object_name_serialize (checksum, OSTREE_OBJECT_TYPE_FILE)); + add_parent_ref (inout_parents, key, parent_key); + g_hash_table_add (inout_reachable, g_steal_pointer (&key)); + } + else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_DIR) + { + char *name; + char *content_checksum; + char *meta_checksum; + + ostree_repo_commit_traverse_iter_get_dir (iter, &name, &content_checksum, + &meta_checksum); + + g_debug ("Found dirtree object %s", content_checksum); + g_debug ("Found dirmeta object %s", meta_checksum); + key = g_variant_ref_sink (ostree_object_name_serialize (meta_checksum, OSTREE_OBJECT_TYPE_DIR_META)); + add_parent_ref (inout_parents, key, parent_key); + g_hash_table_add (inout_reachable, g_steal_pointer (&key)); + + key = g_variant_ref_sink (ostree_object_name_serialize (content_checksum, OSTREE_OBJECT_TYPE_DIR_TREE)); + add_parent_ref (inout_parents, key, parent_key); + if (!g_hash_table_lookup (inout_reachable, key)) + { + if (!traverse_dirtree (repo, content_checksum, key, inout_reachable, inout_parents, + ignore_missing_dirs, cancellable, error)) + return FALSE; + + g_hash_table_add (inout_reachable, g_steal_pointer (&key)); + } + } + else + g_assert_not_reached (); + } + + return TRUE; +} + +static gboolean +traverse_dirtree (OstreeRepo *repo, + const char *checksum, + GVariant *parent_key, + GHashTable *inout_reachable, + GHashTable *inout_parents, + gboolean ignore_missing_dirs, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GError) local_error = NULL; + + g_autoptr(GVariant) dirtree = NULL; + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_DIR_TREE, checksum, + &dirtree, &local_error)) + { + if (ignore_missing_dirs && + g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_debug ("Ignoring not-found dirmeta %s", checksum); + return TRUE; /* Early return */ + } + + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + g_debug ("Traversing dirtree %s", checksum); + ostree_cleanup_repo_commit_traverse_iter + OstreeRepoCommitTraverseIter iter = { 0, }; + if (!ostree_repo_commit_traverse_iter_init_dirtree (&iter, repo, dirtree, + OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE, + error)) + return FALSE; + + if (!traverse_iter (repo, &iter, parent_key, inout_reachable, inout_parents, ignore_missing_dirs, cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_repo_traverse_commit_union_with_parents: (skip) + * @repo: Repo + * @commit_checksum: ASCII SHA256 checksum + * @maxdepth: Traverse this many parent commits, -1 for unlimited + * @inout_reachable: Set of reachable objects + * @inout_parents: Map from object to parent object + * @cancellable: Cancellable + * @error: Error + * + * Update the set @inout_reachable containing all objects reachable + * from @commit_checksum, traversing @maxdepth parent commits. + * + * Additionally this constructs a mapping from each object to the parents + * of the object, which can be used to track which commits an object + * belongs to. + * + * Since: 2018.5 + */ +gboolean +ostree_repo_traverse_commit_union_with_parents (OstreeRepo *repo, + const char *commit_checksum, + int maxdepth, + GHashTable *inout_reachable, + GHashTable *inout_parents, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *tmp_checksum = NULL; + + while (TRUE) + { + g_autoptr(GVariant) key = + g_variant_ref_sink (ostree_object_name_serialize (commit_checksum, OSTREE_OBJECT_TYPE_COMMIT)); + + if (g_hash_table_contains (inout_reachable, key)) + break; + + g_autoptr(GVariant) commit = NULL; + if (!ostree_repo_load_variant_if_exists (repo, OSTREE_OBJECT_TYPE_COMMIT, + commit_checksum, &commit, + error)) + return FALSE; + + /* Just return if the parent isn't found; we do expect most + * people to have partial repositories. + */ + if (!commit) + break; + + /* See if the commit is partial, if so it's not an error to lack objects */ + OstreeRepoCommitState commitstate; + if (!ostree_repo_load_commit (repo, commit_checksum, NULL, &commitstate, + error)) + return FALSE; + + gboolean ignore_missing_dirs = FALSE; + if ((commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) != 0) + ignore_missing_dirs = TRUE; + + g_hash_table_add (inout_reachable, g_variant_ref (key)); + + g_debug ("Traversing commit %s", commit_checksum); + ostree_cleanup_repo_commit_traverse_iter + OstreeRepoCommitTraverseIter iter = { 0, }; + if (!ostree_repo_commit_traverse_iter_init_commit (&iter, repo, commit, + OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE, + error)) + return FALSE; + + if (!traverse_iter (repo, &iter, key, inout_reachable, inout_parents, ignore_missing_dirs, cancellable, error)) + return FALSE; + + gboolean recurse = FALSE; + if (maxdepth == -1 || maxdepth > 0) + { + g_free (tmp_checksum); + tmp_checksum = ostree_commit_get_parent (commit); + if (tmp_checksum) + { + commit_checksum = tmp_checksum; + if (maxdepth > 0) + maxdepth -= 1; + recurse = TRUE; + } + } + if (!recurse) + break; + } + + return TRUE; +} + +/** + * ostree_repo_traverse_commit_union: (skip) + * @repo: Repo + * @commit_checksum: ASCII SHA256 checksum + * @maxdepth: Traverse this many parent commits, -1 for unlimited + * @inout_reachable: Set of reachable objects + * @cancellable: Cancellable + * @error: Error + * + * Update the set @inout_reachable containing all objects reachable + * from @commit_checksum, traversing @maxdepth parent commits. + */ +gboolean +ostree_repo_traverse_commit_union (OstreeRepo *repo, + const char *commit_checksum, + int maxdepth, + GHashTable *inout_reachable, + GCancellable *cancellable, + GError **error) +{ + return + ostree_repo_traverse_commit_union_with_parents (repo, commit_checksum, maxdepth, + inout_reachable, NULL, + cancellable, error); +} + +/** + * ostree_repo_traverse_commit: + * @repo: Repo + * @commit_checksum: ASCII SHA256 checksum + * @maxdepth: Traverse this many parent commits, -1 for unlimited + * @out_reachable: (out) (transfer container) (element-type GVariant GVariant): Set of reachable objects + * @cancellable: Cancellable + * @error: Error + * + * Create a new set @out_reachable containing all objects reachable + * from @commit_checksum, traversing @maxdepth parent commits. + */ +gboolean +ostree_repo_traverse_commit (OstreeRepo *repo, + const char *commit_checksum, + int maxdepth, + GHashTable **out_reachable, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GHashTable) ret_reachable = ostree_repo_traverse_new_reachable (); + if (!ostree_repo_traverse_commit_union (repo, commit_checksum, maxdepth, + ret_reachable, cancellable, error)) + return FALSE; + + if (out_reachable) + *out_reachable = g_steal_pointer (&ret_reachable); + return TRUE; +} diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c new file mode 100644 index 0000000..95eb0ef --- /dev/null +++ b/src/libostree/ostree-repo.c @@ -0,0 +1,6353 @@ +/* + * Copyright (C) 2011 Colin Walters + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include +#include +#include +#include "libglnx.h" +#include "otutil.h" +#include +#include + +#include "ostree-core-private.h" +#include "ostree-sysroot-private.h" +#include "ostree-remote-private.h" +#include "ostree-repo-private.h" +#include "ostree-repo-file.h" +#include "ostree-repo-file-enumerator.h" +#include "ostree-gpg-verifier.h" +#include "ostree-repo-static-delta-private.h" +#include "ot-fs-utils.h" +#include "ostree-autocleanups.h" + +#include +#include +#include +#include +#include + +#define REPO_LOCK_DISABLED (-2) +#define REPO_LOCK_BLOCKING (-1) + +/* ABI Size checks for ostree-repo.h, only for LP64 systems; + * https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models + * + * To generate this data, I used `pahole` from gdb. More concretely, `gdb --args + * /usr/bin/ostree`, then `start`, (to ensure debuginfo was loaded), then e.g. + * `$ pahole OstreeRepoTransactionStats`. + */ +#if __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 8 && __SIZEOF_INT__ == 4 +G_STATIC_ASSERT(sizeof(OstreeRepoTransactionStats) == sizeof(int) * 4 + 8 * 5); +G_STATIC_ASSERT(sizeof(OstreeRepoImportArchiveOptions) == sizeof(int) * 9 + 4 + sizeof(void*) * 8); +G_STATIC_ASSERT(sizeof(OstreeRepoExportArchiveOptions) == sizeof(int) * 9 + 4 + 8 + sizeof(void*) * 8); +G_STATIC_ASSERT(sizeof(OstreeRepoCheckoutAtOptions) == + sizeof(OstreeRepoCheckoutMode) + sizeof(OstreeRepoCheckoutOverwriteMode) + + sizeof(int)*6 + + sizeof(int)*5 + + sizeof(int) + + sizeof(void*)*2 + + sizeof(int)*6 + + sizeof(void*)*7); +G_STATIC_ASSERT(sizeof(OstreeRepoCommitTraverseIter) == + sizeof(int) + sizeof(int) + + sizeof(void*) * 10 + + 130 + 6); /* 6 byte hole */ +G_STATIC_ASSERT(sizeof(OstreeRepoPruneOptions) == + sizeof(OstreeRepoPruneFlags) + + 4 + + sizeof(void*) + + sizeof(int) * 12 + + sizeof(void*) * 7); +#endif + +/** + * SECTION:ostree-repo + * @title: OstreeRepo: Content-addressed object store + * @short_description: A git-like storage system for operating system binaries + * + * The #OstreeRepo is like git, a content-addressed object store. + * Unlike git, it records uid, gid, and extended attributes. + * + * There are four possible "modes" for an #OstreeRepo; %OSTREE_REPO_MODE_BARE + * is very simple - content files are represented exactly as they are, and + * checkouts are just hardlinks. %OSTREE_REPO_MODE_BARE_USER is similar, except + * the uid/gids are not set on the files, and checkouts as hardlinks work only + * for user checkouts. %OSTREE_REPO_MODE_BARE_USER_ONLY is the same as + * BARE_USER, but all metadata is not stored, so it can only be used for user + * checkouts. This mode does not require xattrs. A %OSTREE_REPO_MODE_ARCHIVE + * (also known as %OSTREE_REPO_MODE_ARCHIVE_Z2) repository in contrast stores + * content files zlib-compressed. It is suitable for non-root-owned + * repositories that can be served via a static HTTP server. + * + * Creating an #OstreeRepo does not invoke any file I/O, and thus needs + * to be initialized, either from existing contents or as a new + * repository. If you have an existing repo, use ostree_repo_open() + * to load it from disk and check its validity. To initialize a new + * repository in the given filepath, use ostree_repo_create() instead. + * + * To store content in the repo, first start a transaction with + * ostree_repo_prepare_transaction(). Then create a + * #OstreeMutableTree, and apply functions such as + * ostree_repo_write_directory_to_mtree() to traverse a physical + * filesystem and write content, possibly multiple times. + * + * Once the #OstreeMutableTree is complete, write all of its metadata + * with ostree_repo_write_mtree(), and finally create a commit with + * ostree_repo_write_commit(). + * + * ## Collection IDs + * + * A collection ID is a globally unique identifier which, if set, is used to + * identify refs from a repository which are mirrored elsewhere, such as in + * mirror repositories or peer to peer networks. + * + * This is separate from the `collection-id` configuration key for a remote, which + * is used to store the collection ID of the repository that remote points to. + * + * The collection ID should only be set on an #OstreeRepo if it is the canonical + * collection for some refs. + * + * A collection ID must be a reverse DNS name, where the domain name is under the + * control of the curator of the collection, so they can demonstrate ownership + * of the collection. The later elements in the reverse DNS name can be used to + * disambiguate between multiple collections from the same curator. For example, + * `org.exampleos.Main` and `org.exampleos.Apps`. For the complete format of + * collection IDs, see ostree_validate_collection_id(). + */ +typedef struct { + GObjectClass parent_class; + +#ifndef OSTREE_DISABLE_GPGME + void (*gpg_verify_result) (OstreeRepo *self, + const char *checksum, + OstreeGpgVerifyResult *result); +#endif +} OstreeRepoClass; + +enum { + PROP_0, + + PROP_PATH, + PROP_REMOTES_CONFIG_DIR, + PROP_SYSROOT_PATH +}; + +enum { + GPG_VERIFY_RESULT, + LAST_SIGNAL +}; + +#ifndef OSTREE_DISABLE_GPGME +static guint signals[LAST_SIGNAL] = { 0 }; +#endif + +G_DEFINE_TYPE (OstreeRepo, ostree_repo, G_TYPE_OBJECT) + +#define SYSCONF_REMOTES SHORTENED_SYSCONFDIR "/ostree/remotes.d" + +/* Repository locking + * + * To guard against objects being deleted (e.g., prune) while they're in + * use by another operation is accessing them (e.g., commit), the + * repository must be locked by concurrent writers. + * + * The locking is implemented by maintaining a thread local table of + * lock stacks per repository. This allows thread safe locking since + * each thread maintains its own lock stack. See the OstreeRepoLock type + * below. + * + * The actual locking is done using either open file descriptor locks or + * flock locks. This allows the locking to work with concurrent + * processes. The lock file is held on the ".lock" file within the + * repository. + * + * The intended usage is to take a shared lock when writing objects or + * reading objects in critical sections. Exclusive locks are taken when + * deleting objects. + * + * To allow fine grained locking within libostree, the lock is + * maintained as a stack. The core APIs then push or pop from the stack. + * When pushing or popping a lock state identical to the existing or + * next state, the stack is simply updated. Only when upgrading or + * downgrading the lock (changing to/from unlocked, pushing exclusive on + * shared or popping exclusive to shared) are actual locking operations + * performed. + */ + +static void +free_repo_lock_table (gpointer data) +{ + GHashTable *lock_table = data; + + if (lock_table != NULL) + { + g_debug ("Free lock table"); + g_hash_table_destroy (lock_table); + } +} + +static GPrivate repo_lock_table = G_PRIVATE_INIT (free_repo_lock_table); + +typedef struct { + int fd; + GQueue stack; +} OstreeRepoLock; + +typedef struct { + guint len; + int state; + const char *name; +} OstreeRepoLockInfo; + +static void +repo_lock_info (OstreeRepoLock *lock, OstreeRepoLockInfo *out_info) +{ + g_assert (lock != NULL); + g_assert (out_info != NULL); + + OstreeRepoLockInfo info; + info.len = g_queue_get_length (&lock->stack); + if (info.len == 0) + { + info.state = LOCK_UN; + info.name = "unlocked"; + } + else + { + info.state = GPOINTER_TO_INT (g_queue_peek_head (&lock->stack)); + info.name = (info.state == LOCK_EX) ? "exclusive" : "shared"; + } + + *out_info = info; +} + +static void +free_repo_lock (gpointer data) +{ + OstreeRepoLock *lock = data; + + if (lock != NULL) + { + OstreeRepoLockInfo info; + repo_lock_info (lock, &info); + + g_debug ("Free lock: state=%s, depth=%u", info.name, info.len); + g_queue_clear (&lock->stack); + if (lock->fd >= 0) + { + g_debug ("Closing repo lock file"); + (void) close (lock->fd); + } + g_free (lock); + } +} + +/* Wrapper to handle flock vs OFD locking based on GLnxLockFile */ +static gboolean +do_repo_lock (int fd, + int flags) +{ + int res; + +#ifdef F_OFD_SETLK + struct flock fl = { + .l_type = (flags & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0, + }; + + res = TEMP_FAILURE_RETRY (fcntl (fd, (flags & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl)); +#else + res = -1; + errno = EINVAL; +#endif + + /* Fallback to flock when OFD locks not available */ + if (res < 0) + { + if (errno == EINVAL) + res = TEMP_FAILURE_RETRY (flock (fd, flags)); + if (res < 0) + return FALSE; + } + + return TRUE; +} + +/* Wrapper to handle flock vs OFD unlocking based on GLnxLockFile */ +static gboolean +do_repo_unlock (int fd, + int flags) +{ + int res; + +#ifdef F_OFD_SETLK + struct flock fl = { + .l_type = F_UNLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0, + }; + + res = TEMP_FAILURE_RETRY (fcntl (fd, (flags & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl)); +#else + res = -1; + errno = EINVAL; +#endif + + /* Fallback to flock when OFD locks not available */ + if (res < 0) + { + if (errno == EINVAL) + res = TEMP_FAILURE_RETRY (flock (fd, LOCK_UN | flags)); + if (res < 0) + return FALSE; + } + + return TRUE; +} + +static gboolean +push_repo_lock (OstreeRepo *self, + OstreeRepoLockType lock_type, + gboolean blocking, + GError **error) +{ + int flags = (lock_type == OSTREE_REPO_LOCK_EXCLUSIVE) ? LOCK_EX : LOCK_SH; + if (!blocking) + flags |= LOCK_NB; + + GHashTable *lock_table = g_private_get (&repo_lock_table); + if (lock_table == NULL) + { + g_debug ("Creating repo lock table"); + lock_table = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify)free_repo_lock); + g_private_set (&repo_lock_table, lock_table); + } + + OstreeRepoLock *lock = g_hash_table_lookup (lock_table, self); + if (lock == NULL) + { + lock = g_new0 (OstreeRepoLock, 1); + g_queue_init (&lock->stack); + g_debug ("Opening repo lock file"); + lock->fd = TEMP_FAILURE_RETRY (openat (self->repo_dir_fd, ".lock", + O_CREAT | O_RDWR | O_CLOEXEC, + DEFAULT_REGFILE_MODE)); + if (lock->fd < 0) + { + free_repo_lock (lock); + return glnx_throw_errno_prefix (error, + "Opening lock file %s/.lock failed", + gs_file_get_path_cached (self->repodir)); + } + g_hash_table_insert (lock_table, self, lock); + } + + OstreeRepoLockInfo info; + repo_lock_info (lock, &info); + g_debug ("Push lock: state=%s, depth=%u", info.name, info.len); + + if (info.state == LOCK_EX) + { + g_debug ("Repo already locked exclusively, extending stack"); + g_queue_push_head (&lock->stack, GINT_TO_POINTER (LOCK_EX)); + } + else + { + int next_state = (flags & LOCK_EX) ? LOCK_EX : LOCK_SH; + const char *next_state_name = (flags & LOCK_EX) ? "exclusive" : "shared"; + + g_debug ("Locking repo %s", next_state_name); + if (!do_repo_lock (lock->fd, flags)) + return glnx_throw_errno_prefix (error, "Locking repo %s failed", + next_state_name); + + g_queue_push_head (&lock->stack, GINT_TO_POINTER (next_state)); + } + + return TRUE; +} + +static gboolean +pop_repo_lock (OstreeRepo *self, + gboolean blocking, + GError **error) +{ + int flags = blocking ? 0 : LOCK_NB; + + GHashTable *lock_table = g_private_get (&repo_lock_table); + g_return_val_if_fail (lock_table != NULL, FALSE); + + OstreeRepoLock *lock = g_hash_table_lookup (lock_table, self); + g_return_val_if_fail (lock != NULL, FALSE); + g_return_val_if_fail (lock->fd != -1, FALSE); + + OstreeRepoLockInfo info; + repo_lock_info (lock, &info); + g_return_val_if_fail (info.len > 0, FALSE); + + g_debug ("Pop lock: state=%s, depth=%u", info.name, info.len); + if (info.len > 1) + { + int next_state = GPOINTER_TO_INT (g_queue_peek_nth (&lock->stack, 1)); + + /* Drop back to the previous lock state if it differs */ + if (next_state != info.state) + { + /* We should never drop from shared to exclusive */ + g_return_val_if_fail (next_state == LOCK_SH, FALSE); + g_debug ("Returning lock state to shared"); + if (!do_repo_lock (lock->fd, next_state | flags)) + return glnx_throw_errno_prefix (error, + "Setting repo lock to shared failed"); + } + else + g_debug ("Maintaining lock state as %s", info.name); + } + else + { + /* Lock stack will be empty, unlock */ + g_debug ("Unlocking repo"); + if (!do_repo_unlock (lock->fd, flags)) + return glnx_throw_errno_prefix (error, "Unlocking repo failed"); + } + + g_queue_pop_head (&lock->stack); + + return TRUE; +} + +/* + * ostree_repo_lock_push: + * @self: a #OstreeRepo + * @lock_type: the type of lock to acquire + * @cancellable: a #GCancellable + * @error: a #GError + * + * Takes a lock on the repository and adds it to the lock stack. If @lock_type + * is %OSTREE_REPO_LOCK_SHARED, a shared lock is taken. If @lock_type is + * %OSTREE_REPO_LOCK_EXCLUSIVE, an exclusive lock is taken. The actual lock + * state is only changed when locking a previously unlocked repository or + * upgrading the lock from shared to exclusive. If the requested lock state is + * unchanged or would represent a downgrade (exclusive to shared), the lock + * state is not changed and the stack is simply updated. + * + * ostree_repo_lock_push() waits for the lock depending on the repository's + * lock-timeout-secs configuration. When lock-timeout-secs is -1, a blocking lock is + * attempted. Otherwise, the lock is taken non-blocking and + * ostree_repo_lock_push() will sleep synchronously up to lock-timeout-secs seconds + * attempting to acquire the lock. If the lock cannot be acquired within the + * timeout, a %G_IO_ERROR_WOULD_BLOCK error is returned. + * + * If @self is not writable by the user, then no locking is attempted and + * %TRUE is returned. + * + * Returns: %TRUE on success, otherwise %FALSE with @error set + */ +gboolean +_ostree_repo_lock_push (OstreeRepo *self, + OstreeRepoLockType lock_type, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (self->inited, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (!self->writable) + return TRUE; + + g_assert (self->lock_timeout_seconds >= REPO_LOCK_DISABLED); + if (self->lock_timeout_seconds == REPO_LOCK_DISABLED) + return TRUE; /* No locking */ + else if (self->lock_timeout_seconds == REPO_LOCK_BLOCKING) + { + g_debug ("Pushing lock blocking"); + return push_repo_lock (self, lock_type, TRUE, error); + } + else + { + /* Convert to unsigned to guard against negative values */ + guint lock_timeout_seconds = self->lock_timeout_seconds; + guint waited = 0; + g_debug ("Pushing lock non-blocking with timeout %u", + lock_timeout_seconds); + for (;;) + { + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + g_autoptr(GError) local_error = NULL; + if (push_repo_lock (self, lock_type, FALSE, &local_error)) + return TRUE; + + if (!g_error_matches (local_error, G_IO_ERROR, + G_IO_ERROR_WOULD_BLOCK)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + if (waited >= lock_timeout_seconds) + { + g_debug ("Push lock: Could not acquire lock within %u seconds", + lock_timeout_seconds); + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + /* Sleep 1 second and try again */ + if (waited % 60 == 0) + { + guint remaining = lock_timeout_seconds - waited; + g_debug ("Push lock: Waiting %u more second%s to acquire lock", + remaining, (remaining == 1) ? "" : "s"); + } + waited++; + sleep (1); + } + } +} + +/* + * _ostree_repo_lock_pop: + * @self: a #OstreeRepo + * @cancellable: a #GCancellable + * @error: a #GError + * + * Remove the current repository lock state from the lock stack. If the lock + * stack becomes empty, the repository is unlocked. Otherwise, the lock state + * only changes when transitioning from an exclusive lock back to a shared + * lock. + * + * ostree_repo_lock_pop() waits for the lock depending on the repository's + * lock-timeout-secs configuration. When lock-timeout-secs is -1, a blocking lock is + * attempted. Otherwise, the lock is removed non-blocking and + * ostree_repo_lock_pop() will sleep synchronously up to lock-timeout-secs seconds + * attempting to remove the lock. If the lock cannot be removed within the + * timeout, a %G_IO_ERROR_WOULD_BLOCK error is returned. + * + * If @self is not writable by the user, then no unlocking is attempted and + * %TRUE is returned. + * + * Returns: %TRUE on success, otherwise %FALSE with @error set + */ +gboolean +_ostree_repo_lock_pop (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (self->inited, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (!self->writable) + return TRUE; + + g_assert (self->lock_timeout_seconds >= REPO_LOCK_DISABLED); + if (self->lock_timeout_seconds == REPO_LOCK_DISABLED) + return TRUE; + else if (self->lock_timeout_seconds == REPO_LOCK_BLOCKING) + { + g_debug ("Popping lock blocking"); + return pop_repo_lock (self, TRUE, error); + } + else + { + /* Convert to unsigned to guard against negative values */ + guint lock_timeout_seconds = self->lock_timeout_seconds; + guint waited = 0; + g_debug ("Popping lock non-blocking with timeout %u", + lock_timeout_seconds); + for (;;) + { + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + g_autoptr(GError) local_error = NULL; + if (pop_repo_lock (self, FALSE, &local_error)) + return TRUE; + + if (!g_error_matches (local_error, G_IO_ERROR, + G_IO_ERROR_WOULD_BLOCK)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + if (waited >= lock_timeout_seconds) + { + g_debug ("Pop lock: Could not remove lock within %u seconds", + lock_timeout_seconds); + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + /* Sleep 1 second and try again */ + if (waited % 60 == 0) + { + guint remaining = lock_timeout_seconds - waited; + g_debug ("Pop lock: Waiting %u more second%s to remove lock", + remaining, (remaining == 1) ? "" : "s"); + } + waited++; + sleep (1); + } + } +} + +/* + * _ostree_repo_auto_lock_push: (skip) + * @self: a #OstreeRepo + * @lock_type: the type of lock to acquire + * @cancellable: a #GCancellable + * @error: a #GError + * + * Like ostree_repo_lock_push(), but for usage with #OstreeRepoAutoLock. + * The intended usage is to declare the #OstreeRepoAutoLock with + * g_autoptr() so that ostree_repo_auto_lock_cleanup() is called when it + * goes out of scope. This will automatically pop the lock status off + * the stack if it was acquired successfully. + * + * |[ + * g_autoptr(OstreeRepoAutoLock) lock = NULL; + * lock = _ostree_repo_auto_lock_push (repo, lock_type, cancellable, error); + * if (!lock) + * return FALSE; + * ]| + * + * Returns: @self on success, otherwise %NULL with @error set + */ +OstreeRepoAutoLock * +_ostree_repo_auto_lock_push (OstreeRepo *self, + OstreeRepoLockType lock_type, + GCancellable *cancellable, + GError **error) +{ + if (!_ostree_repo_lock_push (self, lock_type, cancellable, error)) + return NULL; + return (OstreeRepoAutoLock *)self; +} + +/* + * _ostree_repo_auto_lock_cleanup: (skip) + * @lock: a #OstreeRepoAutoLock + * + * A cleanup handler for use with ostree_repo_auto_lock_push(). If @lock is + * not %NULL, ostree_repo_lock_pop() will be called on it. If + * ostree_repo_lock_pop() fails, a critical warning will be emitted. + */ +void +_ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock) +{ + OstreeRepo *repo = lock; + if (repo) + { + g_autoptr(GError) error = NULL; + int errsv = errno; + + if (!_ostree_repo_lock_pop (repo, NULL, &error)) + g_critical ("Cleanup repo lock failed: %s", error->message); + + errno = errsv; + } +} + +static GFile * +get_remotes_d_dir (OstreeRepo *self, + GFile *sysroot); + +OstreeRemote * +_ostree_repo_get_remote (OstreeRepo *self, + const char *name, + GError **error) +{ + OstreeRemote *remote = NULL; + + g_return_val_if_fail (name != NULL, NULL); + + g_mutex_lock (&self->remotes_lock); + + remote = g_hash_table_lookup (self->remotes, name); + + if (remote != NULL) + ostree_remote_ref (remote); + else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Remote \"%s\" not found", name); + + g_mutex_unlock (&self->remotes_lock); + + return remote; +} + +OstreeRemote * +_ostree_repo_get_remote_inherited (OstreeRepo *self, + const char *name, + GError **error) +{ + g_autoptr(OstreeRemote) remote = NULL; + g_autoptr(GError) temp_error = NULL; + + remote = _ostree_repo_get_remote (self, name, &temp_error); + if (remote == NULL) + { + if (self->parent_repo != NULL) + return _ostree_repo_get_remote_inherited (self->parent_repo, name, error); + + g_propagate_error (error, g_steal_pointer (&temp_error)); + return NULL; + } + + return g_steal_pointer (&remote); +} + +gboolean +_ostree_repo_add_remote (OstreeRepo *self, + OstreeRemote *remote) +{ + gboolean already_existed; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (remote != NULL, FALSE); + g_return_val_if_fail (remote->name != NULL, FALSE); + + g_mutex_lock (&self->remotes_lock); + + already_existed = !g_hash_table_replace (self->remotes, remote->name, ostree_remote_ref (remote)); + + g_mutex_unlock (&self->remotes_lock); + + return already_existed; +} + +gboolean +_ostree_repo_remove_remote (OstreeRepo *self, + OstreeRemote *remote) +{ + gboolean removed; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (remote != NULL, FALSE); + g_return_val_if_fail (remote->name != NULL, FALSE); + + g_mutex_lock (&self->remotes_lock); + + removed = g_hash_table_remove (self->remotes, remote->name); + + g_mutex_unlock (&self->remotes_lock); + + return removed; +} + +gboolean +_ostree_repo_remote_name_is_file (const char *remote_name) +{ + return g_str_has_prefix (remote_name, "file://"); +} + +/** + * ostree_repo_get_remote_option: + * @self: A OstreeRepo + * @remote_name: Name + * @option_name: Option + * @default_value: (allow-none): Value returned if @option_name is not present + * @out_value: (out): Return location for value + * @error: Error + * + * OSTree remotes are represented by keyfile groups, formatted like: + * `[remote "remotename"]`. This function returns a value named @option_name + * underneath that group, or @default_value if the remote exists but not the + * option name. If an error is returned, @out_value will be set to %NULL. + * + * Returns: %TRUE on success, otherwise %FALSE with @error set + * + * Since: 2016.5 + */ +gboolean +ostree_repo_get_remote_option (OstreeRepo *self, + const char *remote_name, + const char *option_name, + const char *default_value, + char **out_value, + GError **error) +{ + g_autoptr(OstreeRemote) remote = NULL; + gboolean ret = FALSE; + g_autoptr(GError) temp_error = NULL; + g_autofree char *value = NULL; + + if (_ostree_repo_remote_name_is_file (remote_name)) + { + *out_value = g_strdup (default_value); + return TRUE; + } + + remote = _ostree_repo_get_remote (self, remote_name, &temp_error); + if (remote != NULL) + { + value = g_key_file_get_string (remote->options, remote->group, option_name, &temp_error); + if (value == NULL) + { + if (g_error_matches (temp_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) + { + /* Note: We ignore errors on the parent because the parent config may not + specify this remote, causing a "remote not found" error, but we found + the remote at some point, so we need to instead return the default */ + if (self->parent_repo != NULL && + ostree_repo_get_remote_option (self->parent_repo, + remote_name, option_name, + default_value, + out_value, + NULL)) + return TRUE; + + value = g_strdup (default_value); + ret = TRUE; + } + else + g_propagate_error (error, g_steal_pointer (&temp_error)); + } + else + ret = TRUE; + } + else if (self->parent_repo != NULL) + return ostree_repo_get_remote_option (self->parent_repo, + remote_name, option_name, + default_value, + out_value, + error); + else + g_propagate_error (error, g_steal_pointer (&temp_error)); + + *out_value = g_steal_pointer (&value); + return ret; +} + +/** + * ostree_repo_get_remote_list_option: + * @self: A OstreeRepo + * @remote_name: Name + * @option_name: Option + * @out_value: (out) (array zero-terminated=1): location to store the list + * of strings. The list should be freed with + * g_strfreev(). + * @error: Error + * + * OSTree remotes are represented by keyfile groups, formatted like: + * `[remote "remotename"]`. This function returns a value named @option_name + * underneath that group, and returns it as a zero terminated array of strings. + * If the option is not set, or if an error is returned, @out_value will be set + * to %NULL. + * + * Returns: %TRUE on success, otherwise %FALSE with @error set + * + * Since: 2016.5 + */ +gboolean +ostree_repo_get_remote_list_option (OstreeRepo *self, + const char *remote_name, + const char *option_name, + char ***out_value, + GError **error) +{ + g_autoptr(OstreeRemote) remote = NULL; + gboolean ret = FALSE; + g_autoptr(GError) temp_error = NULL; + g_auto(GStrv) value = NULL; + + if (_ostree_repo_remote_name_is_file (remote_name)) + { + *out_value = NULL; + return TRUE; + } + + remote = _ostree_repo_get_remote (self, remote_name, &temp_error); + if (remote != NULL) + { + value = g_key_file_get_string_list (remote->options, + remote->group, + option_name, + NULL, &temp_error); + + /* Default value if key not found is always NULL. */ + if (g_error_matches (temp_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) + { + /* Note: We ignore errors on the parent because the parent config may not + specify this remote, causing a "remote not found" error, but we found + the remote at some point, so we need to instead return the default */ + if (self->parent_repo != NULL && + ostree_repo_get_remote_list_option (self->parent_repo, + remote_name, option_name, + out_value, + NULL)) + return TRUE; + + ret = TRUE; + } + else if (temp_error) + g_propagate_error (error, g_steal_pointer (&temp_error)); + else + ret = TRUE; + } + else if (self->parent_repo != NULL) + return ostree_repo_get_remote_list_option (self->parent_repo, + remote_name, option_name, + out_value, + error); + else + g_propagate_error (error, g_steal_pointer (&temp_error)); + + *out_value = g_steal_pointer (&value); + return ret; +} + +/** + * ostree_repo_get_remote_boolean_option: + * @self: A OstreeRepo + * @remote_name: Name + * @option_name: Option + * @default_value: Value returned if @option_name is not present + * @out_value: (out) : location to store the result. + * @error: Error + * + * OSTree remotes are represented by keyfile groups, formatted like: + * `[remote "remotename"]`. This function returns a value named @option_name + * underneath that group, and returns it as a boolean. + * If the option is not set, @out_value will be set to @default_value. If an + * error is returned, @out_value will be set to %FALSE. + * + * Returns: %TRUE on success, otherwise %FALSE with @error set + * + * Since: 2016.5 + */ +gboolean +ostree_repo_get_remote_boolean_option (OstreeRepo *self, + const char *remote_name, + const char *option_name, + gboolean default_value, + gboolean *out_value, + GError **error) +{ + g_autoptr(OstreeRemote) remote = NULL; + g_autoptr(GError) temp_error = NULL; + gboolean ret = FALSE; + gboolean value = FALSE; + + if (_ostree_repo_remote_name_is_file (remote_name)) + { + *out_value = default_value; + return TRUE; + } + + remote = _ostree_repo_get_remote (self, remote_name, &temp_error); + if (remote != NULL) + { + value = g_key_file_get_boolean (remote->options, remote->group, option_name, &temp_error); + if (temp_error != NULL) + { + if (g_error_matches (temp_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) + { + /* Note: We ignore errors on the parent because the parent config may not + specify this remote, causing a "remote not found" error, but we found + the remote at some point, so we need to instead return the default */ + if (self->parent_repo != NULL && + ostree_repo_get_remote_boolean_option (self->parent_repo, + remote_name, option_name, + default_value, + out_value, + NULL)) + return TRUE; + + value = default_value; + ret = TRUE; + } + else + g_propagate_error (error, g_steal_pointer (&temp_error)); + } + else + ret = TRUE; + } + else if (self->parent_repo != NULL) + return ostree_repo_get_remote_boolean_option (self->parent_repo, + remote_name, option_name, + default_value, + out_value, + error); + else + g_propagate_error (error, g_steal_pointer (&temp_error)); + + *out_value = value; + return ret; +} + +static void +ostree_repo_finalize (GObject *object) +{ + OstreeRepo *self = OSTREE_REPO (object); + + g_clear_object (&self->parent_repo); + + g_free (self->stagedir_prefix); + g_clear_object (&self->repodir_fdrel); + g_clear_object (&self->repodir); + glnx_close_fd (&self->repo_dir_fd); + glnx_tmpdir_unset (&self->commit_stagedir); + glnx_release_lock_file (&self->commit_stagedir_lock); + glnx_close_fd (&self->tmp_dir_fd); + glnx_close_fd (&self->cache_dir_fd); + glnx_close_fd (&self->objects_dir_fd); + glnx_close_fd (&self->uncompressed_objects_dir_fd); + g_clear_object (&self->sysroot_dir); + g_weak_ref_clear (&self->sysroot); + g_free (self->remotes_config_dir); + + if (self->loose_object_devino_hash) + g_hash_table_destroy (self->loose_object_devino_hash); + if (self->updated_uncompressed_dirs) + g_hash_table_destroy (self->updated_uncompressed_dirs); + if (self->config) + g_key_file_free (self->config); + g_clear_pointer (&self->txn.refs, g_hash_table_destroy); + g_clear_pointer (&self->txn.collection_refs, g_hash_table_destroy); + g_clear_error (&self->writable_error); + g_clear_pointer (&self->object_sizes, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&self->dirmeta_cache, (GDestroyNotify) g_hash_table_unref); + g_mutex_clear (&self->cache_lock); + g_mutex_clear (&self->txn_lock); + g_free (self->collection_id); + g_strfreev (self->repo_finders); + g_free (self->bootloader); + + g_clear_pointer (&self->remotes, g_hash_table_destroy); + g_mutex_clear (&self->remotes_lock); + + GHashTable *lock_table = g_private_get (&repo_lock_table); + if (lock_table) + { + g_hash_table_remove (lock_table, self); + if (g_hash_table_size (lock_table) == 0) + g_private_replace (&repo_lock_table, NULL); + } + + G_OBJECT_CLASS (ostree_repo_parent_class)->finalize (object); +} + +static void +ostree_repo_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeRepo *self = OSTREE_REPO (object); + + switch (prop_id) + { + case PROP_PATH: + self->repodir = g_value_dup_object (value); + break; + case PROP_SYSROOT_PATH: + self->sysroot_dir = g_value_dup_object (value); + break; + case PROP_REMOTES_CONFIG_DIR: + self->remotes_config_dir = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_repo_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeRepo *self = OSTREE_REPO (object); + + switch (prop_id) + { + case PROP_PATH: + g_value_set_object (value, self->repodir); + break; + case PROP_SYSROOT_PATH: + g_value_set_object (value, self->sysroot_dir); + break; + case PROP_REMOTES_CONFIG_DIR: + g_value_set_string (value, self->remotes_config_dir); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_repo_class_init (OstreeRepoClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = ostree_repo_get_property; + object_class->set_property = ostree_repo_set_property; + object_class->finalize = ostree_repo_finalize; + + /** + * OstreeRepo:path: + * + * Path to repository. Note that if this repository was created + * via `ostree_repo_new_at()`, this value will refer to a value in + * the Linux kernel's `/proc/self/fd` directory. Generally, you + * should avoid using this property at all; you can gain a reference + * to the repository's directory fd via `ostree_repo_get_dfd()` and + * use file-descriptor relative operations. + */ + g_object_class_install_property (object_class, + PROP_PATH, + g_param_spec_object ("path", "Path", "Path", + G_TYPE_FILE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + /** + * OstreeRepo:sysroot-path: + * + * A system using libostree for the host has a "system" repository; this + * property will be set for repositories referenced via + * `ostree_sysroot_repo()` for example. + * + * You should avoid using this property; if your code is operating + * on a system repository, use `OstreeSysroot` and access the repository + * object via `ostree_sysroot_repo()`. + */ + g_object_class_install_property (object_class, + PROP_SYSROOT_PATH, + g_param_spec_object ("sysroot-path", + "", + "", + G_TYPE_FILE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + /** + * OstreeRepo:remotes-config-dir: + * + * Path to directory containing remote definitions. The default is `NULL`. + * If a `sysroot-path` property is defined, this value will default to + * `${sysroot_path}/etc/ostree/remotes.d`. + * + * This value will only be used for system repositories. + */ + g_object_class_install_property (object_class, + PROP_REMOTES_CONFIG_DIR, + g_param_spec_string ("remotes-config-dir", + "", + "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + +#ifndef OSTREE_DISABLE_GPGME + /** + * OstreeRepo::gpg-verify-result: + * @self: an #OstreeRepo + * @checksum: checksum of the signed object + * @result: an #OstreeGpgVerifyResult + * + * Emitted during a pull operation upon GPG verification (if enabled). + * Applications can connect to this signal to output the verification + * results if desired. + * + * The signal will be emitted from whichever #GMainContext is the + * thread-default at the point when ostree_repo_pull_with_options() + * is called. + */ + signals[GPG_VERIFY_RESULT] = g_signal_new ("gpg-verify-result", + OSTREE_TYPE_REPO, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (OstreeRepoClass, gpg_verify_result), + NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_STRING, + OSTREE_TYPE_GPG_VERIFY_RESULT); +#endif /* OSTREE_DISABLE_GPGME */ +} + +static void +ostree_repo_init (OstreeRepo *self) +{ + const GDebugKey test_error_keys[] = { + { "pre-commit", OSTREE_REPO_TEST_ERROR_PRE_COMMIT }, + { "invalid-cache", OSTREE_REPO_TEST_ERROR_INVALID_CACHE }, + }; + +#ifndef OSTREE_DISABLE_GPGME + static gsize gpgme_initialized; + + if (g_once_init_enter (&gpgme_initialized)) + { + gpgme_check_version (NULL); + gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL)); + g_once_init_leave (&gpgme_initialized, 1); + } +#endif + + self->test_error_flags = g_parse_debug_string (g_getenv ("OSTREE_REPO_TEST_ERROR"), + test_error_keys, G_N_ELEMENTS (test_error_keys)); + + g_mutex_init (&self->cache_lock); + g_mutex_init (&self->txn_lock); + + self->remotes = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) ostree_remote_unref); + g_mutex_init (&self->remotes_lock); + + self->repo_dir_fd = -1; + self->cache_dir_fd = -1; + self->tmp_dir_fd = -1; + self->objects_dir_fd = -1; + self->uncompressed_objects_dir_fd = -1; + self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_UNKNOWN; +} + +/** + * ostree_repo_new: + * @path: Path to a repository + * + * Returns: (transfer full): An accessor object for an OSTree repository located at @path + */ +OstreeRepo* +ostree_repo_new (GFile *path) +{ + return g_object_new (OSTREE_TYPE_REPO, "path", path, NULL); +} + +static OstreeRepo * +repo_open_at_take_fd (int *dfd, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepo) repo = g_object_new (OSTREE_TYPE_REPO, NULL); + repo->repo_dir_fd = glnx_steal_fd (dfd); + + if (!ostree_repo_open (repo, cancellable, error)) + return NULL; + return g_steal_pointer (&repo); +} + +/** + * ostree_repo_open_at: + * @dfd: Directory fd + * @path: Path + * + * This combines ostree_repo_new() (but using fd-relative access) with + * ostree_repo_open(). Use this when you know you should be operating on an + * already extant repository. If you want to create one, use ostree_repo_create_at(). + * + * Returns: (transfer full): An accessor object for an OSTree repository located at @dfd + @path + * + * Since: 2017.10 + */ +OstreeRepo* +ostree_repo_open_at (int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int repo_dfd = -1; + if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error)) + return NULL; + + return repo_open_at_take_fd (&repo_dfd, cancellable, error); +} + +static GFile * +get_default_repo_path (GFile *sysroot_path) +{ + if (sysroot_path == NULL) + sysroot_path = _ostree_get_default_sysroot_path (); + + return g_file_resolve_relative_path (sysroot_path, "ostree/repo"); +} + +/** + * ostree_repo_new_for_sysroot_path: + * @repo_path: Path to a repository + * @sysroot_path: Path to the system root + * + * Creates a new #OstreeRepo instance, taking the system root path explicitly + * instead of assuming "/". + * + * Returns: (transfer full): An accessor object for the OSTree repository located at @repo_path. + */ +OstreeRepo * +ostree_repo_new_for_sysroot_path (GFile *repo_path, + GFile *sysroot_path) +{ + return g_object_new (OSTREE_TYPE_REPO, "path", repo_path, "sysroot-path", sysroot_path, NULL); +} + +/** + * ostree_repo_new_default: + * + * If the current working directory appears to be an OSTree + * repository, create a new #OstreeRepo object for accessing it. + * Otherwise use the path in the OSTREE_REPO environment variable + * (if defined) or else the default system repository located at + * /ostree/repo. + * + * Returns: (transfer full): An accessor object for an OSTree repository located at /ostree/repo + */ +OstreeRepo* +ostree_repo_new_default (void) +{ + if (g_file_test ("objects", G_FILE_TEST_IS_DIR) + && g_file_test ("config", G_FILE_TEST_IS_REGULAR)) + { + g_autoptr(GFile) cwd = g_file_new_for_path ("."); + return ostree_repo_new (cwd); + } + else + { + const char *envvar = g_getenv ("OSTREE_REPO"); + g_autoptr(GFile) repo_path = NULL; + + if (envvar == NULL || *envvar == '\0') + repo_path = get_default_repo_path (NULL); + else + repo_path = g_file_new_for_path (envvar); + + return ostree_repo_new (repo_path); + } +} + +/** + * ostree_repo_is_system: + * @repo: Repository + * + * Returns: %TRUE if this repository is the root-owned system global repository + */ +gboolean +ostree_repo_is_system (OstreeRepo *repo) +{ + g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE); + + /* If we were created via ostree_sysroot_get_repo(), we know the answer is yes + * without having to compare file paths. + */ + if (repo->sysroot_kind == OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT || + repo->sysroot_kind == OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE) + return TRUE; + + /* No sysroot_dir set? Not a system repo then. */ + if (!repo->sysroot_dir) + return FALSE; + + /* If we created via ostree_repo_new(), we'll have a repo path. Compare + * it to the sysroot path in that case. + */ + if (repo->repodir) + { + g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir); + return g_file_equal (repo->repodir, default_repo_path); + } + /* Otherwise, not a system repo */ + return FALSE; +} + +/** + * ostree_repo_is_writable: + * @self: Repo + * @error: a #GError + * + * Returns whether the repository is writable by the current user. + * If the repository is not writable, the @error indicates why. + * + * Returns: %TRUE if this repository is writable + */ +gboolean +ostree_repo_is_writable (OstreeRepo *self, + GError **error) +{ + g_return_val_if_fail (self->inited, FALSE); + + if (error != NULL && self->writable_error != NULL) + *error = g_error_copy (self->writable_error); + + return self->writable; +} + +/** + * _ostree_repo_update_mtime: + * @self: Repo + * @error: a #GError + * + * Bump the mtime of the repository so that programs + * can detect that the refs have updated. + */ +gboolean +_ostree_repo_update_mtime (OstreeRepo *self, + GError **error) +{ + if (futimens (self->repo_dir_fd, NULL) != 0) + { + glnx_set_prefix_error_from_errno (error, "%s", "futimens"); + return FALSE; + } + return TRUE; +} + +/** + * ostree_repo_get_config: + * @self: + * + * Returns: (transfer none): The repository configuration; do not modify + */ +GKeyFile * +ostree_repo_get_config (OstreeRepo *self) +{ + g_return_val_if_fail (self->inited, NULL); + + return self->config; +} + +/** + * ostree_repo_copy_config: + * @self: + * + * Returns: (transfer full): A newly-allocated copy of the repository config + */ +GKeyFile * +ostree_repo_copy_config (OstreeRepo *self) +{ + GKeyFile *copy; + char *data; + gsize len; + + g_return_val_if_fail (self->inited, NULL); + + copy = g_key_file_new (); + data = g_key_file_to_data (self->config, &len, NULL); + if (!g_key_file_load_from_data (copy, data, len, 0, NULL)) + g_assert_not_reached (); + g_free (data); + return copy; +} + +/** + * ostree_repo_write_config: + * @self: Repo + * @new_config: Overwrite the config file with this data + * @error: a #GError + * + * Save @new_config in place of this repository's config file. + */ +gboolean +ostree_repo_write_config (OstreeRepo *self, + GKeyFile *new_config, + GError **error) +{ + g_return_val_if_fail (self->inited, FALSE); + + /* Ensure that any remotes in the new config aren't defined in a + * separate config file. + */ + gsize num_groups; + g_auto(GStrv) groups = g_key_file_get_groups (new_config, &num_groups); + for (gsize i = 0; i < num_groups; i++) + { + g_autoptr(OstreeRemote) new_remote = ostree_remote_new_from_keyfile (new_config, groups[i]); + if (new_remote != NULL) + { + g_autoptr(GError) local_error = NULL; + + g_autoptr(OstreeRemote) cur_remote = + _ostree_repo_get_remote (self, new_remote->name, &local_error); + if (cur_remote == NULL) + { + if (!g_error_matches (local_error, G_IO_ERROR, + G_IO_ERROR_NOT_FOUND)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + else if (cur_remote->file != NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "Remote \"%s\" already defined in %s", + new_remote->name, + gs_file_get_path_cached (cur_remote->file)); + return FALSE; + } + } + } + + gsize len; + g_autofree char *data = g_key_file_to_data (new_config, &len, error); + if (!glnx_file_replace_contents_at (self->repo_dir_fd, "config", + (guint8*)data, len, 0, + NULL, error)) + return FALSE; + + g_key_file_free (self->config); + self->config = g_key_file_new (); + if (!g_key_file_load_from_data (self->config, data, len, 0, error)) + return FALSE; + + return TRUE; +} + +/* Bind a subset of an a{sv} to options in a given GKeyfile section */ +static void +keyfile_set_from_vardict (GKeyFile *keyfile, + const char *section, + GVariant *vardict) +{ + GVariantIter viter; + const char *key; + GVariant *val; + + g_variant_iter_init (&viter, vardict); + while (g_variant_iter_loop (&viter, "{&s@v}", &key, &val)) + { + g_autoptr(GVariant) child = g_variant_get_variant (val); + if (g_variant_is_of_type (child, G_VARIANT_TYPE_STRING)) + g_key_file_set_string (keyfile, section, key, g_variant_get_string (child, NULL)); + else if (g_variant_is_of_type (child, G_VARIANT_TYPE_BOOLEAN)) + g_key_file_set_boolean (keyfile, section, key, g_variant_get_boolean (child)); + else if (g_variant_is_of_type (child, G_VARIANT_TYPE_STRING_ARRAY)) + { + gsize len; + g_autofree const gchar **strv_child = g_variant_get_strv (child, &len); + g_key_file_set_string_list (keyfile, section, key, strv_child, len); + } + else + g_critical ("Unhandled type '%s' in %s", + (char*)g_variant_get_type (child), G_STRFUNC); + } +} + +static gboolean +impl_repo_remote_add (OstreeRepo *self, + GFile *sysroot, + gboolean if_not_exists, + const char *name, + const char *url, + GVariant *options, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (url != NULL, FALSE); + g_return_val_if_fail (options == NULL || g_variant_is_of_type (options, G_VARIANT_TYPE ("a{sv}")), FALSE); + + if (!ostree_validate_remote_name (name, error)) + return FALSE; + + g_autoptr(OstreeRemote) remote = _ostree_repo_get_remote (self, name, NULL); + if (remote != NULL && if_not_exists) + { + /* Note early return */ + return TRUE; + } + else if (remote != NULL) + { + return glnx_throw (error, + "Remote configuration for \"%s\" already exists: %s", + name, remote->file ? gs_file_get_path_cached (remote->file) : "(in config)"); + } + + remote = ostree_remote_new (name); + + /* Only add repos in remotes.d if the repo option + * add-remotes-config-dir is true. This is the default for system + * repos. + */ + g_autoptr(GFile) etc_ostree_remotes_d = get_remotes_d_dir (self, sysroot); + if (etc_ostree_remotes_d && self->add_remotes_config_dir) + { + g_autoptr(GError) local_error = NULL; + + if (!g_file_make_directory_with_parents (etc_ostree_remotes_d, + cancellable, &local_error)) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + { + g_clear_error (&local_error); + } + else + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + + g_autofree char *basename = g_strconcat (name, ".conf", NULL); + remote->file = g_file_get_child (etc_ostree_remotes_d, basename); + } + + if (g_str_has_prefix (url, "metalink=")) + g_key_file_set_string (remote->options, remote->group, "metalink", url + strlen ("metalink=")); + else + g_key_file_set_string (remote->options, remote->group, "url", url); + + if (options) + keyfile_set_from_vardict (remote->options, remote->group, options); + + if (remote->file != NULL) + { + gsize length; + g_autofree char *data = g_key_file_to_data (remote->options, &length, NULL); + + if (!g_file_replace_contents (remote->file, + data, length, + NULL, FALSE, 0, NULL, + cancellable, error)) + return FALSE; + } + else + { + g_autoptr(GKeyFile) config = NULL; + + config = ostree_repo_copy_config (self); + ot_keyfile_copy_group (remote->options, config, remote->group); + + if (!ostree_repo_write_config (self, config, error)) + return FALSE; + } + + _ostree_repo_add_remote (self, remote); + + return TRUE; +} + +/** + * ostree_repo_remote_add: + * @self: Repo + * @name: Name of remote + * @url: URL for remote (if URL begins with metalink=, it will be used as such) + * @options: (allow-none): GVariant of type a{sv} + * @cancellable: Cancellable + * @error: Error + * + * Create a new remote named @name pointing to @url. If @options is + * provided, then it will be mapped to #GKeyFile entries, where the + * GVariant dictionary key is an option string, and the value is + * mapped as follows: + * * s: g_key_file_set_string() + * * b: g_key_file_set_boolean() + * * as: g_key_file_set_string_list() + * + */ +gboolean +ostree_repo_remote_add (OstreeRepo *self, + const char *name, + const char *url, + GVariant *options, + GCancellable *cancellable, + GError **error) +{ + return impl_repo_remote_add (self, NULL, FALSE, name, url, options, + cancellable, error); +} + +static gboolean +impl_repo_remote_delete (OstreeRepo *self, + GFile *sysroot, + gboolean if_exists, + const char *name, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (name != NULL, FALSE); + + if (!ostree_validate_remote_name (name, error)) + return FALSE; + + g_autoptr(OstreeRemote) remote = NULL; + if (if_exists) + { + remote = _ostree_repo_get_remote (self, name, NULL); + if (!remote) + { + /* Note early return */ + return TRUE; + } + } + else + remote = _ostree_repo_get_remote (self, name, error); + + if (remote == NULL) + return FALSE; + + if (remote->file != NULL) + { + if (!glnx_unlinkat (AT_FDCWD, gs_file_get_path_cached (remote->file), 0, error)) + return FALSE; + } + else + { + g_autoptr(GKeyFile) config = ostree_repo_copy_config (self); + + /* XXX Not sure it's worth failing if the group to remove + * isn't found. It's the end result we want, after all. */ + if (g_key_file_remove_group (config, remote->group, NULL)) + { + if (!ostree_repo_write_config (self, config, error)) + return FALSE; + } + } + + /* Delete the remote's keyring file, if it exists. */ + if (!ot_ensure_unlinked_at (self->repo_dir_fd, remote->keyring, error)) + return FALSE; + + _ostree_repo_remove_remote (self, remote); + + return TRUE; +} + +/** + * ostree_repo_remote_delete: + * @self: Repo + * @name: Name of remote + * @cancellable: Cancellable + * @error: Error + * + * Delete the remote named @name. It is an error if the provided + * remote does not exist. + * + */ +gboolean +ostree_repo_remote_delete (OstreeRepo *self, + const char *name, + GCancellable *cancellable, + GError **error) +{ + return impl_repo_remote_delete (self, NULL, FALSE, name, cancellable, error); +} + + +static gboolean +impl_repo_remote_replace (OstreeRepo *self, + GFile *sysroot, + const char *name, + const char *url, + GVariant *options, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (url != NULL, FALSE); + g_return_val_if_fail (options == NULL || g_variant_is_of_type (options, G_VARIANT_TYPE ("a{sv}")), FALSE); + + if (!ostree_validate_remote_name (name, error)) + return FALSE; + + g_autoptr(GError) local_error = NULL; + g_autoptr(OstreeRemote) remote = _ostree_repo_get_remote (self, name, &local_error); + if (remote == NULL) + { + if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + g_clear_error (&local_error); + if (!impl_repo_remote_add (self, sysroot, FALSE, name, url, options, + cancellable, error)) + return FALSE; + } + else + { + /* Replace the entire option group */ + if (!g_key_file_remove_group (remote->options, remote->group, error)) + return FALSE; + + if (g_str_has_prefix (url, "metalink=")) + g_key_file_set_string (remote->options, remote->group, "metalink", + url + strlen ("metalink=")); + else + g_key_file_set_string (remote->options, remote->group, "url", url); + + if (options != NULL) + keyfile_set_from_vardict (remote->options, remote->group, options); + + /* Write out updated settings */ + if (remote->file != NULL) + { + gsize length; + g_autofree char *data = g_key_file_to_data (remote->options, &length, + NULL); + + if (!g_file_replace_contents (remote->file, data, length, + NULL, FALSE, 0, NULL, + cancellable, error)) + return FALSE; + } + else + { + g_autoptr(GKeyFile) config = ostree_repo_copy_config (self); + + /* Remove the existing group if it exists */ + if (!g_key_file_remove_group (config, remote->group, &local_error)) + { + if (!g_error_matches (local_error, G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + + ot_keyfile_copy_group (remote->options, config, remote->group); + if (!ostree_repo_write_config (self, config, error)) + return FALSE; + } + } + + return TRUE; +} + +/** + * ostree_repo_remote_change: + * @self: Repo + * @sysroot: (allow-none): System root + * @changeop: Operation to perform + * @name: Name of remote + * @url: URL for remote (if URL begins with metalink=, it will be used as such) + * @options: (allow-none): GVariant of type a{sv} + * @cancellable: Cancellable + * @error: Error + * + * A combined function handling the equivalent of + * ostree_repo_remote_add(), ostree_repo_remote_delete(), with more + * options. + * + * + */ +gboolean +ostree_repo_remote_change (OstreeRepo *self, + GFile *sysroot, + OstreeRepoRemoteChange changeop, + const char *name, + const char *url, + GVariant *options, + GCancellable *cancellable, + GError **error) +{ + switch (changeop) + { + case OSTREE_REPO_REMOTE_CHANGE_ADD: + return impl_repo_remote_add (self, sysroot, FALSE, name, url, options, + cancellable, error); + case OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS: + return impl_repo_remote_add (self, sysroot, TRUE, name, url, options, + cancellable, error); + case OSTREE_REPO_REMOTE_CHANGE_DELETE: + return impl_repo_remote_delete (self, sysroot, FALSE, name, + cancellable, error); + case OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS: + return impl_repo_remote_delete (self, sysroot, TRUE, name, + cancellable, error); + case OSTREE_REPO_REMOTE_CHANGE_REPLACE: + return impl_repo_remote_replace (self, sysroot, name, url, options, + cancellable, error); + } + g_assert_not_reached (); +} + +static void +_ostree_repo_remote_list (OstreeRepo *self, + GHashTable *out) +{ + GHashTableIter iter; + gpointer key, value; + + g_mutex_lock (&self->remotes_lock); + + g_hash_table_iter_init (&iter, self->remotes); + while (g_hash_table_iter_next (&iter, &key, &value)) + g_hash_table_insert (out, g_strdup (key), NULL); + + g_mutex_unlock (&self->remotes_lock); + + if (self->parent_repo) + _ostree_repo_remote_list (self->parent_repo, out); +} + +/** + * ostree_repo_remote_list: + * @self: Repo + * @out_n_remotes: (out) (allow-none): Number of remotes available + * + * List available remote names in an #OstreeRepo. Remote names are sorted + * alphabetically. If no remotes are available the function returns %NULL. + * + * Returns: (array length=out_n_remotes) (transfer full): a %NULL-terminated + * array of remote names + **/ +char ** +ostree_repo_remote_list (OstreeRepo *self, + guint *out_n_remotes) +{ + char **remotes = NULL; + guint n_remotes; + g_autoptr(GHashTable) remotes_ht = NULL; + + remotes_ht = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) NULL); + + _ostree_repo_remote_list (self, remotes_ht); + + n_remotes = g_hash_table_size (remotes_ht); + + if (n_remotes > 0) + { + GList *list, *link; + guint ii = 0; + + remotes = g_new (char *, n_remotes + 1); + + list = g_hash_table_get_keys (remotes_ht); + list = g_list_sort (list, (GCompareFunc) strcmp); + + for (link = list; link != NULL; link = link->next) + remotes[ii++] = g_strdup (link->data); + + g_list_free (list); + + remotes[ii] = NULL; + } + + if (out_n_remotes) + *out_n_remotes = n_remotes; + + return remotes; +} + +/** + * ostree_repo_remote_get_url: + * @self: Repo + * @name: Name of remote + * @out_url: (out) (allow-none): Remote's URL + * @error: Error + * + * Return the URL of the remote named @name through @out_url. It is an + * error if the provided remote does not exist. + * + * Returns: %TRUE on success, %FALSE on failure + */ +gboolean +ostree_repo_remote_get_url (OstreeRepo *self, + const char *name, + char **out_url, + GError **error) +{ + g_return_val_if_fail (name != NULL, FALSE); + + g_autofree char *url = NULL; + if (_ostree_repo_remote_name_is_file (name)) + { + url = g_strdup (name); + } + else + { + if (!ostree_repo_get_remote_option (self, name, "url", NULL, &url, error)) + return FALSE; + + if (url == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No \"url\" option in remote \"%s\"", name); + return FALSE; + } + } + + if (out_url != NULL) + *out_url = g_steal_pointer (&url); + return TRUE; +} + +/** + * ostree_repo_remote_get_gpg_verify: + * @self: Repo + * @name: Name of remote + * @out_gpg_verify: (out) (allow-none): Remote's GPG option + * @error: Error + * + * Return whether GPG verification is enabled for the remote named @name + * through @out_gpg_verify. It is an error if the provided remote does + * not exist. + * + * Returns: %TRUE on success, %FALSE on failure + */ +gboolean +ostree_repo_remote_get_gpg_verify (OstreeRepo *self, + const char *name, + gboolean *out_gpg_verify, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + /* For compatibility with pull-local, don't GPG verify file:// URIs. */ + if (_ostree_repo_remote_name_is_file (name)) + { + if (out_gpg_verify != NULL) + *out_gpg_verify = FALSE; + return TRUE; + } + + return ostree_repo_get_remote_boolean_option (self, name, "gpg-verify", + TRUE, out_gpg_verify, error); +} + +/** + * ostree_repo_remote_get_gpg_verify_summary: + * @self: Repo + * @name: Name of remote + * @out_gpg_verify_summary: (out) (allow-none): Remote's GPG option + * @error: Error + * + * Return whether GPG verification of the summary is enabled for the remote + * named @name through @out_gpg_verify_summary. It is an error if the provided + * remote does not exist. + * + * Returns: %TRUE on success, %FALSE on failure + */ +gboolean +ostree_repo_remote_get_gpg_verify_summary (OstreeRepo *self, + const char *name, + gboolean *out_gpg_verify_summary, + GError **error) +{ + return ostree_repo_get_remote_boolean_option (self, name, "gpg-verify-summary", + FALSE, out_gpg_verify_summary, error); +} + +/** + * ostree_repo_remote_gpg_import: + * @self: Self + * @name: name of a remote + * @source_stream: (nullable): a #GInputStream, or %NULL + * @key_ids: (array zero-terminated=1) (element-type utf8) (nullable): a %NULL-terminated array of GPG key IDs, or %NULL + * @out_imported: (out) (optional): return location for the number of imported + * keys, or %NULL + * @cancellable: a #GCancellable + * @error: a #GError + * + * Imports one or more GPG keys from the open @source_stream, or from the + * user's personal keyring if @source_stream is %NULL. The @key_ids array + * can optionally restrict which keys are imported. If @key_ids is %NULL, + * then all keys are imported. + * + * The imported keys will be used to conduct GPG verification when pulling + * from the remote named @name. + * + * Returns: %TRUE on success, %FALSE on failure + */ +gboolean +ostree_repo_remote_gpg_import (OstreeRepo *self, + const char *name, + GInputStream *source_stream, + const char * const *key_ids, + guint *out_imported, + GCancellable *cancellable, + GError **error) +{ +#ifndef OSTREE_DISABLE_GPGME + OstreeRemote *remote; + g_auto(gpgme_ctx_t) source_context = NULL; + g_auto(gpgme_ctx_t) target_context = NULL; + g_auto(gpgme_data_t) data_buffer = NULL; + gpgme_import_result_t import_result; + gpgme_import_status_t import_status; + g_autofree char *source_tmp_dir = NULL; + g_autofree char *target_tmp_dir = NULL; + glnx_autofd int target_temp_fd = -1; + g_autoptr(GPtrArray) keys = NULL; + struct stat stbuf; + gpgme_error_t gpg_error; + gboolean ret = FALSE; + + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + /* First make sure the remote name is valid. */ + + remote = _ostree_repo_get_remote_inherited (self, name, error); + if (remote == NULL) + goto out; + + /* Prepare the source GPGME context. If reading GPG keys from an input + * stream, point the OpenPGP engine at a temporary directory and import + * the keys to a new pubring.gpg file. If the key data format is ASCII + * armored, this step will convert them to binary. */ + + source_context = ot_gpgme_new_ctx (NULL, error); + if (!source_context) + goto out; + + if (source_stream != NULL) + { + data_buffer = ot_gpgme_data_input (source_stream); + + if (!ot_gpgme_ctx_tmp_home_dir (source_context, &source_tmp_dir, + NULL, cancellable, error)) + { + g_prefix_error (error, "Unable to configure context: "); + goto out; + } + + gpg_error = gpgme_op_import (source_context, data_buffer); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to import keys"); + goto out; + } + + g_clear_pointer (&data_buffer, (GDestroyNotify) gpgme_data_release); + } + + /* Retrieve all keys or specific keys from the source GPGME context. + * Assemble a NULL-terminated array of gpgme_key_t structs to import. */ + + /* The keys array will contain a NULL terminator, but it turns out, + * although not documented, gpgme_key_unref() gracefully handles it. */ + keys = g_ptr_array_new_with_free_func ((GDestroyNotify) gpgme_key_unref); + + if (key_ids != NULL) + { + guint ii; + + for (ii = 0; key_ids[ii] != NULL; ii++) + { + gpgme_key_t key = NULL; + + gpg_error = gpgme_get_key (source_context, key_ids[ii], &key, 0); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to find key \"%s\"", key_ids[ii]); + goto out; + } + + /* Transfer ownership. */ + g_ptr_array_add (keys, key); + } + } + else + { + gpg_error = gpgme_op_keylist_start (source_context, NULL, 0); + + while (gpg_error == GPG_ERR_NO_ERROR) + { + gpgme_key_t key = NULL; + + gpg_error = gpgme_op_keylist_next (source_context, &key); + + if (gpg_error != GPG_ERR_NO_ERROR) + break; + + /* Transfer ownership. */ + g_ptr_array_add (keys, key); + } + + if (gpgme_err_code (gpg_error) != GPG_ERR_EOF) + { + ot_gpgme_throw (gpg_error, error, "Unable to list keys"); + goto out; + } + } + + /* Add the NULL terminator. */ + g_ptr_array_add (keys, NULL); + + /* Prepare the target GPGME context to serve as the import destination. + * Here the pubring.gpg file in a second temporary directory is a copy + * of the remote's keyring file. We'll let the import operation alter + * the pubring.gpg file, then rename it back to its permanent home. */ + + target_context = ot_gpgme_new_ctx (NULL, error); + if (!target_context) + goto out; + + /* No need for an output stream since we copy in a pubring.gpg. */ + if (!ot_gpgme_ctx_tmp_home_dir (target_context, &target_tmp_dir, + NULL, cancellable, error)) + { + g_prefix_error (error, "Unable to configure context: "); + goto out; + } + + if (!glnx_opendirat (AT_FDCWD, target_tmp_dir, FALSE, &target_temp_fd, error)) + { + g_prefix_error (error, "Unable to open directory: "); + goto out; + } + + if (fstatat (self->repo_dir_fd, remote->keyring, &stbuf, AT_SYMLINK_NOFOLLOW) == 0) + { + if (!glnx_file_copy_at (self->repo_dir_fd, remote->keyring, + &stbuf, target_temp_fd, "pubring.gpg", + GLNX_FILE_COPY_NOXATTRS, cancellable, error)) + { + g_prefix_error (error, "Unable to copy remote's keyring: "); + goto out; + } + } + else if (errno == ENOENT) + { + glnx_autofd int fd = -1; + + /* Create an empty pubring.gpg file prior to importing keys. This + * prevents gpg2 from creating a pubring.kbx file in the new keybox + * format [1]. We want to stay with the older keyring format since + * its performance issues are not relevant here. + * + * [1] https://gnupg.org/faq/whats-new-in-2.1.html#keybox + */ + fd = openat (target_temp_fd, "pubring.gpg", + O_WRONLY | O_CREAT | O_CLOEXEC | O_NOCTTY, 0644); + if (fd == -1) + { + glnx_set_prefix_error_from_errno (error, "%s", "Unable to create pubring.gpg"); + goto out; + } + } + else + { + glnx_set_prefix_error_from_errno (error, "%s", "Unable to copy remote's keyring"); + goto out; + } + + /* Export the selected keys from the source context and import them into + * the target context. */ + + gpg_error = gpgme_data_new (&data_buffer); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to create data buffer"); + goto out; + } + + gpg_error = gpgme_op_export_keys (source_context, + (gpgme_key_t *) keys->pdata, 0, + data_buffer); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to export keys"); + goto out; + } + + (void) gpgme_data_seek (data_buffer, 0, SEEK_SET); + + gpg_error = gpgme_op_import (target_context, data_buffer); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to import keys"); + goto out; + } + + import_result = gpgme_op_import_result (target_context); + g_return_val_if_fail (import_result != NULL, FALSE); + + /* Check the status of each import and fail on the first error. + * All imports must be successful to update the remote's keyring. */ + for (import_status = import_result->imports; + import_status != NULL; + import_status = import_status->next) + { + if (import_status->result != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "Unable to import key \"%s\"", + import_status->fpr); + goto out; + } + } + + /* Import successful; replace the remote's old keyring with the + * updated keyring in the target context's temporary directory. */ + if (!glnx_file_copy_at (target_temp_fd, "pubring.gpg", NULL, + self->repo_dir_fd, remote->keyring, + GLNX_FILE_COPY_NOXATTRS | GLNX_FILE_COPY_OVERWRITE, + cancellable, error)) + goto out; + + if (out_imported != NULL) + *out_imported = (guint) import_result->imported; + + ret = TRUE; + +out: + if (remote != NULL) + ostree_remote_unref (remote); + + if (source_tmp_dir != NULL) { + ot_gpgme_kill_agent (source_tmp_dir); + (void) glnx_shutil_rm_rf_at (AT_FDCWD, source_tmp_dir, NULL, NULL); + } + + if (target_tmp_dir != NULL) { + ot_gpgme_kill_agent (target_tmp_dir); + (void) glnx_shutil_rm_rf_at (AT_FDCWD, target_tmp_dir, NULL, NULL); + } + + g_prefix_error (error, "GPG: "); + + return ret; +#else /* OSTREE_DISABLE_GPGME */ + return glnx_throw (error, "GPG feature is disabled in a build time"); +#endif /* OSTREE_DISABLE_GPGME */ +} + +/** + * ostree_repo_remote_fetch_summary: + * @self: Self + * @name: name of a remote + * @out_summary: (out) (optional): return location for raw summary data, or + * %NULL + * @out_signatures: (out) (optional): return location for raw summary + * signature data, or %NULL + * @cancellable: a #GCancellable + * @error: a #GError + * + * Tries to fetch the summary file and any GPG signatures on the summary file + * over HTTP, and returns the binary data in @out_summary and @out_signatures + * respectively. + * + * If no summary file exists on the remote server, @out_summary is set to + * @NULL. Likewise if the summary file is not signed, @out_signatures is + * set to @NULL. In either case the function still returns %TRUE. + * + * This method does not verify the signature of the downloaded summary file. + * Use ostree_repo_verify_summary() for that. + * + * Parse the summary data into a #GVariant using g_variant_new_from_bytes() + * with #OSTREE_SUMMARY_GVARIANT_FORMAT as the format string. + * + * Returns: %TRUE on success, %FALSE on failure + */ +gboolean +ostree_repo_remote_fetch_summary (OstreeRepo *self, + const char *name, + GBytes **out_summary, + GBytes **out_signatures, + GCancellable *cancellable, + GError **error) +{ + return ostree_repo_remote_fetch_summary_with_options (self, + name, + NULL, + out_summary, + out_signatures, + cancellable, + error); +} + +static gboolean +ostree_repo_mode_to_string (OstreeRepoMode mode, + const char **out_mode, + GError **error) +{ + const char *ret_mode; + + switch (mode) + { + case OSTREE_REPO_MODE_BARE: + ret_mode = "bare"; + break; + case OSTREE_REPO_MODE_BARE_USER: + ret_mode = "bare-user"; + break; + case OSTREE_REPO_MODE_BARE_USER_ONLY: + ret_mode = "bare-user-only"; + break; + case OSTREE_REPO_MODE_ARCHIVE: + /* Legacy alias */ + ret_mode ="archive-z2"; + break; + default: + return glnx_throw (error, "Invalid mode '%d'", mode); + } + + *out_mode = ret_mode; + return TRUE; +} + +/** + * ostree_repo_mode_from_string: + * @mode: a repo mode as a string + * @out_mode: (out): the corresponding #OstreeRepoMode + * @error: a #GError if the string is not a valid mode + */ +gboolean +ostree_repo_mode_from_string (const char *mode, + OstreeRepoMode *out_mode, + GError **error) +{ + OstreeRepoMode ret_mode; + + if (strcmp (mode, "bare") == 0) + ret_mode = OSTREE_REPO_MODE_BARE; + else if (strcmp (mode, "bare-user") == 0) + ret_mode = OSTREE_REPO_MODE_BARE_USER; + else if (strcmp (mode, "bare-user-only") == 0) + ret_mode = OSTREE_REPO_MODE_BARE_USER_ONLY; + else if (strcmp (mode, "archive-z2") == 0 || + strcmp (mode, "archive") == 0) + ret_mode = OSTREE_REPO_MODE_ARCHIVE; + else + return glnx_throw (error, "Invalid mode '%s' in repository configuration", mode); + + *out_mode = ret_mode; + return TRUE; +} + +#define DEFAULT_CONFIG_CONTENTS ("[core]\n" \ + "repo_version=1\n") + +/* Just write the dirs to disk, return a dfd */ +static gboolean +repo_create_at_internal (int dfd, + const char *path, + OstreeRepoMode mode, + GVariant *options, + int *out_dfd, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Creating repo", error); + struct stat stbuf; + /* We do objects/ last - if it exists we do nothing and exit successfully */ + const char *state_dirs[] = { "tmp", "extensions", "state", + "refs", "refs/heads", "refs/mirrors", + "refs/remotes", "objects" }; + + /* Early return if we have an existing repo */ + { g_autofree char *objects_path = g_build_filename (path, "objects", NULL); + + if (!glnx_fstatat_allow_noent (dfd, objects_path, &stbuf, 0, error)) + return FALSE; + if (errno == 0) + { + glnx_autofd int repo_dfd = -1; + if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error)) + return FALSE; + + /* Note early return */ + *out_dfd = glnx_steal_fd (&repo_dfd); + return TRUE; + } + } + + if (mkdirat (dfd, path, DEFAULT_DIRECTORY_MODE) != 0) + { + if (G_UNLIKELY (errno != EEXIST)) + return glnx_throw_errno_prefix (error, "mkdirat"); + } + + glnx_autofd int repo_dfd = -1; + if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error)) + return FALSE; + + if (!glnx_fstatat_allow_noent (repo_dfd, "config", &stbuf, 0, error)) + return FALSE; + if (errno == ENOENT) + { + const char *mode_str = NULL; + g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS); + + if (!ostree_repo_mode_to_string (mode, &mode_str, error)) + return FALSE; + g_assert (mode_str); + + g_string_append_printf (config_data, "mode=%s\n", mode_str); + + const char *collection_id = NULL; + if (options) + g_variant_lookup (options, "collection-id", "&s", &collection_id); + if (collection_id != NULL) + g_string_append_printf (config_data, "collection-id=%s\n", collection_id); + + if (!glnx_file_replace_contents_at (repo_dfd, "config", + (guint8*)config_data->str, config_data->len, + 0, cancellable, error)) + return FALSE; + } + + for (guint i = 0; i < G_N_ELEMENTS (state_dirs); i++) + { + const char *elt = state_dirs[i]; + if (mkdirat (repo_dfd, elt, DEFAULT_DIRECTORY_MODE) == -1) + { + if (G_UNLIKELY (errno != EEXIST)) + return glnx_throw_errno_prefix (error, "mkdirat"); + } + } + + /* Test that the fs supports user xattrs now, so we get an error early rather + * than during an object write later. + */ + if (mode == OSTREE_REPO_MODE_BARE_USER) + { + g_auto(GLnxTmpfile) tmpf = { 0, }; + + if (!glnx_open_tmpfile_linkable_at (repo_dfd, ".", O_RDWR|O_CLOEXEC, &tmpf, error)) + return FALSE; + if (!_ostree_write_bareuser_metadata (tmpf.fd, 0, 0, 644, NULL, error)) + return FALSE; + } + + *out_dfd = glnx_steal_fd (&repo_dfd); + return TRUE; +} + +/** + * ostree_repo_create: + * @self: An #OstreeRepo + * @mode: The mode to store the repository in + * @cancellable: Cancellable + * @error: Error + * + * Create the underlying structure on disk for the repository, and call + * ostree_repo_open() on the result, preparing it for use. + + * Since version 2016.8, this function will succeed on an existing + * repository, and finish creating any necessary files in a partially + * created repository. However, this function cannot change the mode + * of an existing repository, and will silently ignore an attempt to + * do so. + * + * Since 2017.9, "existing repository" is defined by the existence of an + * `objects` subdirectory. + * + * This function predates ostree_repo_create_at(). It is an error to call + * this function on a repository initialized via ostree_repo_open_at(). + */ +gboolean +ostree_repo_create (OstreeRepo *self, + OstreeRepoMode mode, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (self->repodir, FALSE); + const char *repopath = gs_file_get_path_cached (self->repodir); + g_autoptr(GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + if (self->collection_id) + g_variant_builder_add (builder, "{s@v}", "collection-id", + g_variant_new_variant (g_variant_new_string (self->collection_id))); + + glnx_autofd int repo_dir_fd = -1; + g_autoptr(GVariant) options = g_variant_ref_sink (g_variant_builder_end (builder)); + if (!repo_create_at_internal (AT_FDCWD, repopath, mode, + options, + &repo_dir_fd, + cancellable, error)) + return FALSE; + self->repo_dir_fd = glnx_steal_fd (&repo_dir_fd); + if (!ostree_repo_open (self, cancellable, error)) + return FALSE; + return TRUE; +} + +/** + * ostree_repo_create_at: + * @dfd: Directory fd + * @path: Path + * @mode: The mode to store the repository in + * @options: a{sv}: See below for accepted keys + * @cancellable: Cancellable + * @error: Error + * + * This is a file-descriptor relative version of ostree_repo_create(). + * Create the underlying structure on disk for the repository, and call + * ostree_repo_open_at() on the result, preparing it for use. + * + * If a repository already exists at @dfd + @path (defined by an `objects/` + * subdirectory existing), then this function will simply call + * ostree_repo_open_at(). In other words, this function cannot be used to change + * the mode or configuration (`repo/config`) of an existing repo. + * + * The @options dict may contain: + * + * - collection-id: s: Set as collection ID in repo/config (Since 2017.9) + * + * Returns: (transfer full): A new OSTree repository reference + * + * Since: 2017.10 + */ +OstreeRepo * +ostree_repo_create_at (int dfd, + const char *path, + OstreeRepoMode mode, + GVariant *options, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int repo_dfd = -1; + if (!repo_create_at_internal (dfd, path, mode, options, &repo_dfd, + cancellable, error)) + return NULL; + return repo_open_at_take_fd (&repo_dfd, cancellable, error); +} + +static gboolean +enumerate_directory_allow_noent (GFile *dirpath, + const char *queryargs, + GFileQueryInfoFlags queryflags, + GFileEnumerator **out_direnum, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GError) temp_error = NULL; + g_autoptr(GFileEnumerator) ret_direnum = NULL; + + ret_direnum = g_file_enumerate_children (dirpath, queryargs, queryflags, + cancellable, &temp_error); + if (!ret_direnum) + { + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + g_clear_error (&temp_error); + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + return FALSE; + } + } + + if (out_direnum) + *out_direnum = g_steal_pointer (&ret_direnum); + return TRUE; +} + +static gboolean +add_remotes_from_keyfile (OstreeRepo *self, + GKeyFile *keyfile, + GFile *file, + GError **error) +{ + GQueue queue = G_QUEUE_INIT; + g_auto(GStrv) groups = NULL; + gsize length, ii; + gboolean ret = FALSE; + + g_mutex_lock (&self->remotes_lock); + + groups = g_key_file_get_groups (keyfile, &length); + + for (ii = 0; ii < length; ii++) + { + OstreeRemote *remote; + + remote = ostree_remote_new_from_keyfile (keyfile, groups[ii]); + + if (remote != NULL) + { + /* Make sure all the remotes in the key file are + * acceptable before adding any to the OstreeRepo. */ + g_queue_push_tail (&queue, remote); + + if (g_hash_table_contains (self->remotes, remote->name)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Multiple specifications found for remote \"%s\"", + remote->name); + goto out; + } + + if (file != NULL) + remote->file = g_object_ref (file); + } + } + + while (!g_queue_is_empty (&queue)) + { + OstreeRemote *remote = g_queue_pop_head (&queue); + g_hash_table_replace (self->remotes, remote->name, remote); + } + + ret = TRUE; + + out: + while (!g_queue_is_empty (&queue)) + ostree_remote_unref (g_queue_pop_head (&queue)); + + g_mutex_unlock (&self->remotes_lock); + + return ret; +} + +static gboolean +append_one_remote_config (OstreeRepo *self, + GFile *path, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GKeyFile) remotedata = g_key_file_new (); + if (!g_key_file_load_from_file (remotedata, gs_file_get_path_cached (path), + 0, error)) + return FALSE; + + return add_remotes_from_keyfile (self, remotedata, path, error); +} + +static GFile * +get_remotes_d_dir (OstreeRepo *self, + GFile *sysroot) +{ + g_autoptr(GFile) sysroot_owned = NULL; + /* Very complicated sysroot logic; this bit breaks the otherwise mostly clean + * layering between OstreeRepo and OstreeSysroot. First, If a sysroot was + * provided, use it. Otherwise, check to see whether we reference + * /ostree/repo, or if not that, see if we have a ref to a sysroot (and it's + * physical). + */ + g_autoptr(OstreeSysroot) sysroot_ref = NULL; + if (sysroot == NULL) + { + /* No explicit sysroot? Let's see if we have a kind */ + switch (self->sysroot_kind) + { + case OSTREE_REPO_SYSROOT_KIND_UNKNOWN: + g_assert_not_reached (); + break; + case OSTREE_REPO_SYSROOT_KIND_NO: + break; + case OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE: + sysroot = sysroot_owned = g_file_new_for_path ("/"); + break; + case OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT: + sysroot_ref = (OstreeSysroot*)g_weak_ref_get (&self->sysroot); + /* Only write to /etc/ostree/remotes.d if we are pointed at a deployment */ + if (sysroot_ref != NULL && !sysroot_ref->is_physical) + sysroot = ostree_sysroot_get_path (sysroot_ref); + break; + } + } + /* For backwards compat, also fall back to the sysroot-path variable, which we + * don't set anymore internally, and I hope no one else uses. + */ + if (sysroot == NULL && sysroot_ref == NULL) + sysroot = self->sysroot_dir; + + /* Was the config directory specified? If so, use that with the + * optional sysroot prepended. If not, return the path in /etc if the + * sysroot was found and NULL otherwise to use the repo config. + */ + if (self->remotes_config_dir != NULL) + { + if (sysroot == NULL) + return g_file_new_for_path (self->remotes_config_dir); + else + return g_file_resolve_relative_path (sysroot, self->remotes_config_dir); + } + else if (sysroot == NULL) + return NULL; + else + return g_file_resolve_relative_path (sysroot, SYSCONF_REMOTES); +} + +static gboolean +min_free_space_calculate_reserved_bytes (OstreeRepo *self, guint64 *bytes, GError **error) +{ + guint64 reserved_bytes = 0; + + struct statvfs stvfsbuf; + if (TEMP_FAILURE_RETRY (fstatvfs (self->repo_dir_fd, &stvfsbuf)) < 0) + return glnx_throw_errno_prefix (error, "fstatvfs"); + + if (self->min_free_space_mb > 0) + { + if (self->min_free_space_mb > (G_MAXUINT64 >> 20)) + return glnx_throw (error, "min-free-space value is greater than the maximum allowed value of %" G_GUINT64_FORMAT " bytes", + (G_MAXUINT64 >> 20)); + + reserved_bytes = self->min_free_space_mb << 20; + } + else if (self->min_free_space_percent > 0) + { + if (stvfsbuf.f_frsize > (G_MAXUINT64 / stvfsbuf.f_blocks)) + return glnx_throw (error, "Filesystem's size is greater than the maximum allowed value of %" G_GUINT64_FORMAT " bytes", + (G_MAXUINT64 / stvfsbuf.f_blocks)); + + guint64 total_bytes = (stvfsbuf.f_frsize * stvfsbuf.f_blocks); + reserved_bytes = ((double)total_bytes) * (self->min_free_space_percent/100.0); + } + + *bytes = reserved_bytes; + return TRUE; +} + +static gboolean +min_free_space_size_validate_and_convert (OstreeRepo *self, + const char *min_free_space_size_str, + GError **error) +{ + static GRegex *regex; + static gsize regex_initialized; + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^([0-9]+)(G|M|T)B$", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + g_autoptr(GMatchInfo) match = NULL; + if (!g_regex_match (regex, min_free_space_size_str, 0, &match)) + return glnx_throw (error, "It should be of the format '123MB', '123GB' or '123TB'"); + + g_autofree char *size_str = g_match_info_fetch (match, 1); + g_autofree char *unit = g_match_info_fetch (match, 2); + guint shifts; + + switch (*unit) + { + case 'M': + shifts = 0; + break; + case 'G': + shifts = 10; + break; + case 'T': + shifts = 20; + break; + default: + g_assert_not_reached (); + } + + guint64 min_free_space = g_ascii_strtoull (size_str, NULL, 10); + if (shifts > 0 && g_bit_nth_lsf (min_free_space, 63 - shifts) != -1) + return glnx_throw (error, "Value was too high"); + + self->min_free_space_mb = min_free_space << shifts; + + return TRUE; +} + +static gboolean +reload_core_config (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *version = NULL; + g_autofree char *mode = NULL; + g_autofree char *contents = NULL; + g_autofree char *parent_repo_path = NULL; + gboolean is_archive; + gsize len; + + g_clear_pointer (&self->config, (GDestroyNotify)g_key_file_unref); + self->config = g_key_file_new (); + + contents = glnx_file_get_contents_utf8_at (self->repo_dir_fd, "config", &len, + NULL, error); + if (!contents) + return FALSE; + if (!g_key_file_load_from_data (self->config, contents, len, 0, error)) + { + g_prefix_error (error, "Couldn't parse config file: "); + return FALSE; + } + + version = g_key_file_get_value (self->config, "core", "repo_version", error); + if (!version) + return FALSE; + + if (strcmp (version, "1") != 0) + return glnx_throw (error, "Invalid repository version '%s'", version); + + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "archive", + FALSE, &is_archive, error)) + return FALSE; + if (is_archive) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of OSTree no longer supports \"archive\" repositories; use archive-z2 instead"); + return FALSE; + } + + if (!ot_keyfile_get_value_with_default (self->config, "core", "mode", + "bare", &mode, error)) + return FALSE; + if (!ostree_repo_mode_from_string (mode, &self->mode, error)) + return FALSE; + + if (self->writable) + { + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "enable-uncompressed-cache", + TRUE, &self->enable_uncompressed_cache, error)) + return FALSE; + } + else + self->enable_uncompressed_cache = FALSE; + + { + gboolean do_fsync; + + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "fsync", + TRUE, &do_fsync, error)) + return FALSE; + + if (!do_fsync) + ostree_repo_set_disable_fsync (self, TRUE); + } + + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "per-object-fsync", + FALSE, &self->per_object_fsync, error)) + return FALSE; + + /* See https://github.com/ostreedev/ostree/issues/758 */ + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "disable-xattrs", + FALSE, &self->disable_xattrs, error)) + return FALSE; + + { g_autofree char *tmp_expiry_seconds = NULL; + + /* 86400 secs = one day */ + if (!ot_keyfile_get_value_with_default (self->config, "core", "tmp-expiry-secs", "86400", + &tmp_expiry_seconds, error)) + return FALSE; + + self->tmp_expiry_seconds = g_ascii_strtoull (tmp_expiry_seconds, NULL, 10); + } + + { gboolean locking; + /* Enabled by default in 2018.05 */ + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "locking", + TRUE, &locking, error)) + return FALSE; + if (!locking) + { + self->lock_timeout_seconds = REPO_LOCK_DISABLED; + } + else + { + g_autofree char *lock_timeout_seconds = NULL; + + if (!ot_keyfile_get_value_with_default (self->config, "core", "lock-timeout-secs", "30", + &lock_timeout_seconds, error)) + return FALSE; + + self->lock_timeout_seconds = g_ascii_strtoll (lock_timeout_seconds, NULL, 10); + } + } + + { g_autofree char *compression_level_str = NULL; + + /* gzip defaults to 6 */ + (void)ot_keyfile_get_value_with_default (self->config, "archive", "zlib-level", NULL, + &compression_level_str, NULL); + + if (compression_level_str) + /* Ensure level is in [1,9] */ + self->zlib_compression_level = MAX (1, MIN (9, g_ascii_strtoull (compression_level_str, NULL, 10))); + else + self->zlib_compression_level = OSTREE_ARCHIVE_DEFAULT_COMPRESSION_LEVEL; + } + + { + /* Try to parse both min-free-space-* config options first. If both are absent, fallback on 3% free space. + * If both are present and are non-zero, use min-free-space-size unconditionally and display a warning. + */ + if (g_key_file_has_key (self->config, "core", "min-free-space-size", NULL)) + { + g_autofree char *min_free_space_size_str = NULL; + + if (!ot_keyfile_get_value_with_default (self->config, "core", "min-free-space-size", + NULL, &min_free_space_size_str, error)) + return FALSE; + + /* Validate the string and convert the size to MBs */ + if (!min_free_space_size_validate_and_convert (self, min_free_space_size_str, error)) + return glnx_prefix_error (error, "Invalid min-free-space-size '%s'", min_free_space_size_str); + } + + if (g_key_file_has_key (self->config, "core", "min-free-space-percent", NULL)) + { + g_autofree char *min_free_space_percent_str = NULL; + + if (!ot_keyfile_get_value_with_default (self->config, "core", "min-free-space-percent", + NULL, &min_free_space_percent_str, error)) + return FALSE; + + self->min_free_space_percent = g_ascii_strtoull (min_free_space_percent_str, NULL, 10); + if (self->min_free_space_percent > 99) + return glnx_throw (error, "Invalid min-free-space-percent '%s'", min_free_space_percent_str); + } + else if (!g_key_file_has_key (self->config, "core", "min-free-space-size", NULL)) + { + /* Default fallback of 3% free space. If changing this, be sure to change the man page too */ + self->min_free_space_percent = 3; + self->min_free_space_mb = 0; + } + + if (self->min_free_space_percent != 0 && self->min_free_space_mb != 0) + { + self->min_free_space_percent = 0; + g_debug ("Both min-free-space-percent and -size are mentioned in config. Enforcing min-free-space-size check only."); + } + } + + /* Currently experimental */ + static const char fsverity_key[] = "ex-fsverity"; + self->fs_verity_wanted = _OSTREE_FEATURE_NO; +#ifdef HAVE_LINUX_FSVERITY_H + self->fs_verity_supported = _OSTREE_FEATURE_MAYBE; +#else + self->fs_verity_supported = _OSTREE_FEATURE_NO; +#endif + gboolean fsverity_required = FALSE; + if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "required", + FALSE, &fsverity_required, error)) + return FALSE; + if (fsverity_required) + { + self->fs_verity_wanted = _OSTREE_FEATURE_YES; + if (self->fs_verity_supported == _OSTREE_FEATURE_NO) + return glnx_throw (error, "fsverity required, but libostree compiled without support"); + } + else + { + gboolean fsverity_opportunistic = FALSE; + if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "opportunistic", + FALSE, &fsverity_opportunistic, error)) + return FALSE; + if (fsverity_opportunistic) + self->fs_verity_wanted = _OSTREE_FEATURE_MAYBE; + } + + { + g_clear_pointer (&self->collection_id, g_free); + if (!ot_keyfile_get_value_with_default (self->config, "core", "collection-id", + NULL, &self->collection_id, NULL)) + return FALSE; + } + + if (!ot_keyfile_get_value_with_default (self->config, "core", "parent", + NULL, &parent_repo_path, error)) + return FALSE; + + if (parent_repo_path && parent_repo_path[0]) + { + g_autoptr(GFile) parent_repo_f = g_file_new_for_path (parent_repo_path); + + g_clear_object (&self->parent_repo); + self->parent_repo = ostree_repo_new (parent_repo_f); + + if (!ostree_repo_open (self->parent_repo, cancellable, error)) + { + g_prefix_error (error, "While checking parent repository '%s': ", + gs_file_get_path_cached (parent_repo_f)); + return FALSE; + } + } + + /* By default, only add remotes in a remotes config directory for + * system repos. This is to preserve legacy behavior for non-system + * repos that specify a remotes config dir (flatpak). + */ + { gboolean is_system = ostree_repo_is_system (self); + + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "add-remotes-config-dir", + is_system, &self->add_remotes_config_dir, error)) + return FALSE; + } + + { g_autofree char *payload_threshold = NULL; + + if (!ot_keyfile_get_value_with_default (self->config, "core", "payload-link-threshold", "-1", + &payload_threshold, error)) + return FALSE; + + self->payload_link_threshold = g_ascii_strtoull (payload_threshold, NULL, 10); + } + + { g_auto(GStrv) configured_finders = NULL; + g_autoptr(GError) local_error = NULL; + + configured_finders = g_key_file_get_string_list (self->config, "core", "default-repo-finders", + NULL, &local_error); + if (g_error_matches (local_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) + g_clear_error (&local_error); + else if (local_error != NULL) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + if (configured_finders != NULL && *configured_finders == NULL) + return glnx_throw (error, "Invalid empty default-repo-finders configuration"); + + for (char **iter = configured_finders; iter && *iter; iter++) + { + const char *repo_finder = *iter; + + if (strcmp (repo_finder, "config") != 0 && + strcmp (repo_finder, "lan") != 0 && + strcmp (repo_finder, "mount") != 0) + return glnx_throw (error, "Invalid configured repo-finder '%s'", repo_finder); + } + + /* Fall back to a default set of finders */ + if (configured_finders == NULL) + configured_finders = g_strsplit ("config;mount", ";", -1); + + g_clear_pointer (&self->repo_finders, g_strfreev); + self->repo_finders = g_steal_pointer (&configured_finders); + } + + return TRUE; +} + +static gboolean +reload_remote_config (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + + g_mutex_lock (&self->remotes_lock); + g_hash_table_remove_all (self->remotes); + g_mutex_unlock (&self->remotes_lock); + + if (!add_remotes_from_keyfile (self, self->config, NULL, error)) + return FALSE; + + g_autoptr(GFile) remotes_d = get_remotes_d_dir (self, NULL); + if (remotes_d == NULL) + return TRUE; + + g_autoptr(GFileEnumerator) direnum = NULL; + if (!enumerate_directory_allow_noent (remotes_d, OSTREE_GIO_FAST_QUERYINFO, 0, + &direnum, + cancellable, error)) + return FALSE; + if (direnum) + { + while (TRUE) + { + GFileInfo *file_info; + GFile *path; + const char *name; + guint32 type; + + if (!g_file_enumerator_iterate (direnum, &file_info, &path, + NULL, error)) + return FALSE; + if (file_info == NULL) + break; + + name = g_file_info_get_attribute_byte_string (file_info, "standard::name"); + type = g_file_info_get_attribute_uint32 (file_info, "standard::type"); + + if (type == G_FILE_TYPE_REGULAR && + g_str_has_suffix (name, ".conf")) + { + if (!append_one_remote_config (self, path, cancellable, error)) + return FALSE; + } + } + } + + return TRUE; +} + +static gboolean +reload_sysroot_config (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + { g_autofree char *bootloader = NULL; + + if (!ot_keyfile_get_value_with_default_group_optional (self->config, "sysroot", + "bootloader", "auto", + &bootloader, error)) + return FALSE; + + /* TODO: possibly later add support for specifying a generic bootloader + * binary "x" in /usr/lib/ostree/bootloaders/x). See: + * https://github.com/ostreedev/ostree/issues/1719 + * https://github.com/ostreedev/ostree/issues/1801 + * Also, dedup these strings with the bootloader implementations + */ + if (!(g_str_equal (bootloader, "auto") || g_str_equal (bootloader, "none") + || g_str_equal (bootloader, "zipl"))) + return glnx_throw (error, "Invalid bootloader configuration: '%s'", bootloader); + + g_free (self->bootloader); + self->bootloader = g_steal_pointer (&bootloader); + } + + return TRUE; +} + +/** + * ostree_repo_reload_config: + * @self: repo + * @cancellable: cancellable + * @error: error + * + * By default, an #OstreeRepo will cache the remote configuration and its + * own repo/config data. This API can be used to reload it. + * + * Since: 2017.2 + */ +gboolean +ostree_repo_reload_config (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + if (!reload_core_config (self, cancellable, error)) + return FALSE; + if (!reload_remote_config (self, cancellable, error)) + return FALSE; + if (!reload_sysroot_config (self, cancellable, error)) + return FALSE; + return TRUE; +} + +gboolean +ostree_repo_open (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("opening repo", error); + + struct stat stbuf; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (self->inited) + return TRUE; + + /* We use a directory of the form `staging-${BOOT_ID}-${RANDOM}` + * where if the ${BOOT_ID} doesn't match, we know file contents + * possibly haven't been sync'd to disk and need to be discarded. + */ + { const char *env_bootid = getenv ("OSTREE_BOOTID"); + g_autofree char *boot_id = NULL; + + if (env_bootid != NULL) + boot_id = g_strdup (env_bootid); + else + { + if (!g_file_get_contents ("/proc/sys/kernel/random/boot_id", + &boot_id, + NULL, + error)) + return FALSE; + g_strdelimit (boot_id, "\n", '\0'); + } + + self->stagedir_prefix = g_strconcat (OSTREE_REPO_TMPDIR_STAGING, boot_id, "-", NULL); + } + + if (self->repo_dir_fd == -1) + { + g_assert (self->repodir); + if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE, + &self->repo_dir_fd, error)) + return FALSE; + } + + if (!glnx_fstat (self->repo_dir_fd, &stbuf, error)) + return FALSE; + self->device = stbuf.st_dev; + self->inode = stbuf.st_ino; + + if (!glnx_opendirat (self->repo_dir_fd, "objects", TRUE, + &self->objects_dir_fd, error)) + return FALSE; + + self->writable = faccessat (self->objects_dir_fd, ".", W_OK, 0) == 0; + if (!self->writable) + { + /* This is returned through ostree_repo_is_writable(). */ + glnx_set_error_from_errno (&self->writable_error); + /* Note - we don't return this error yet! */ + } + + if (!glnx_fstat (self->objects_dir_fd, &stbuf, error)) + return FALSE; + self->owner_uid = stbuf.st_uid; + + if (self->writable) + { + /* Always try to recreate the tmpdir to be nice to people + * who are looking to free up space. + * + * https://github.com/ostreedev/ostree/issues/1018 + */ + if (mkdirat (self->repo_dir_fd, "tmp", DEFAULT_DIRECTORY_MODE) == -1) + { + if (G_UNLIKELY (errno != EEXIST)) + return glnx_throw_errno_prefix (error, "mkdir(tmp)"); + } + } + + if (!glnx_opendirat (self->repo_dir_fd, "tmp", TRUE, &self->tmp_dir_fd, error)) + return FALSE; + + if (self->writable) + { + if (!glnx_shutil_mkdir_p_at (self->tmp_dir_fd, _OSTREE_CACHE_DIR, DEFAULT_DIRECTORY_MODE, cancellable, error)) + return FALSE; + + if (!glnx_opendirat (self->tmp_dir_fd, _OSTREE_CACHE_DIR, TRUE, &self->cache_dir_fd, error)) + return FALSE; + } + + /* If we weren't created via ostree_sysroot_get_repo(), for backwards + * compatibility we need to figure out now whether or not we refer to the + * system repo. See also ostree-sysroot.c. + */ + if (self->sysroot_kind == OSTREE_REPO_SYSROOT_KIND_UNKNOWN) + { + struct stat system_stbuf; + /* Ignore any errors if we can't access /ostree/repo */ + if (fstatat (AT_FDCWD, "/ostree/repo", &system_stbuf, 0) == 0) + { + /* Are we the same as /ostree/repo? */ + if (self->device == system_stbuf.st_dev && + self->inode == system_stbuf.st_ino) + self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE; + else + self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO; + } + else + self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO; + } + + if (!ostree_repo_reload_config (self, cancellable, error)) + return FALSE; + + self->inited = TRUE; + return TRUE; +} + +/** + * ostree_repo_set_disable_fsync: + * @self: An #OstreeRepo + * @disable_fsync: If %TRUE, do not fsync + * + * Disable requests to fsync() to stable storage during commits. This + * option should only be used by build system tools which are creating + * disposable virtual machines, or have higher level mechanisms for + * ensuring data consistency. + */ +void +ostree_repo_set_disable_fsync (OstreeRepo *self, + gboolean disable_fsync) +{ + self->disable_fsync = disable_fsync; +} + +/** + * ostree_repo_set_cache_dir: + * @self: An #OstreeRepo + * @dfd: directory fd + * @path: subpath in @dfd + * @cancellable: a #GCancellable + * @error: a #GError + * + * Set a custom location for the cache directory used for e.g. + * per-remote summary caches. Setting this manually is useful when + * doing operations on a system repo as a user because you don't have + * write permissions in the repo, where the cache is normally stored. + * + * Since: 2016.5 + */ +gboolean +ostree_repo_set_cache_dir (OstreeRepo *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int fd = -1; + if (!glnx_opendirat (dfd, path, TRUE, &fd, error)) + return FALSE; + + glnx_close_fd (&self->cache_dir_fd); + self->cache_dir_fd = glnx_steal_fd (&fd); + + return TRUE; +} + +/** + * ostree_repo_get_disable_fsync: + * @self: An #OstreeRepo + * + * For more information see ostree_repo_set_disable_fsync(). + * + * Returns: Whether or not fsync() is enabled for this repo. + */ +gboolean +ostree_repo_get_disable_fsync (OstreeRepo *self) +{ + return self->disable_fsync; +} + +/* Replace the contents of a file, honoring the repository's fsync + * policy. + */ +gboolean +_ostree_repo_file_replace_contents (OstreeRepo *self, + int dfd, + const char *path, + const guint8 *buf, + gsize len, + GCancellable *cancellable, + GError **error) +{ + return glnx_file_replace_contents_at (dfd, path, buf, len, + self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW, + cancellable, error); +} + +/** + * ostree_repo_get_path: + * @self: Repo + * + * Note that since the introduction of ostree_repo_open_at(), this function may + * return a process-specific path in `/proc` if the repository was created using + * that API. In general, you should avoid use of this API. + * + * Returns: (transfer none): Path to repo + */ +GFile * +ostree_repo_get_path (OstreeRepo *self) +{ + /* Did we have an abspath? Return it */ + if (self->repodir) + return self->repodir; + /* Lazily create a fd-relative path */ + if (!self->repodir_fdrel) + self->repodir_fdrel = ot_fdrel_to_gfile (self->repo_dir_fd, "."); + return self->repodir_fdrel; +} + +/** + * ostree_repo_get_dfd: + * @self: Repo + * + * In some cases it's useful for applications to access the repository + * directly; for example, writing content into `repo/tmp` ensures it's + * on the same filesystem. Another case is detecting the mtime on the + * repository (to see whether a ref was written). + * + * Returns: File descriptor for repository root - owned by @self + * Since: 2016.4 + */ +int +ostree_repo_get_dfd (OstreeRepo *self) +{ + g_return_val_if_fail (self->repo_dir_fd != -1, -1); + return self->repo_dir_fd; +} + +/** + * ostree_repo_hash: + * @self: an #OstreeRepo + * + * Calculate a hash value for the given open repository, suitable for use when + * putting it into a hash table. It is an error to call this on an #OstreeRepo + * which is not yet open, as a persistent hash value cannot be calculated until + * the repository is open and the inode of its root directory has been loaded. + * + * This function does no I/O. + * + * Returns: hash value for the #OstreeRepo + * Since: 2017.12 + */ +guint +ostree_repo_hash (OstreeRepo *self) +{ + g_return_val_if_fail (OSTREE_IS_REPO (self), 0); + + /* We cannot hash non-open repositories, since their hash value would change + * once they’re opened, resulting in false lookup misses and the inability to + * remove them from a hash table. */ + g_assert (self->repo_dir_fd >= 0); + + /* device and inode numbers are distributed fairly uniformly, so we can’t + * do much better than just combining them. No need to rehash to even out + * the distribution. */ + return (self->device ^ self->inode); +} + +/** + * ostree_repo_equal: + * @a: an #OstreeRepo + * @b: an #OstreeRepo + * + * Check whether two opened repositories are the same on disk: if their root + * directories are the same inode. If @a or @b are not open yet (due to + * ostree_repo_open() not being called on them yet), %FALSE will be returned. + * + * Returns: %TRUE if @a and @b are the same repository on disk, %FALSE otherwise + * Since: 2017.12 + */ +gboolean +ostree_repo_equal (OstreeRepo *a, + OstreeRepo *b) +{ + g_return_val_if_fail (OSTREE_IS_REPO (a), FALSE); + g_return_val_if_fail (OSTREE_IS_REPO (b), FALSE); + + if (a->repo_dir_fd < 0 || b->repo_dir_fd < 0) + return FALSE; + + return (a->device == b->device && a->inode == b->inode); +} + +OstreeRepoMode +ostree_repo_get_mode (OstreeRepo *self) +{ + g_return_val_if_fail (self->inited, FALSE); + + return self->mode; +} + +/** + * ostree_repo_get_min_free_space_bytes: + * @self: Repo + * @out_reserved_bytes: (out): Location to store the result + * @error: Return location for a #GError + * + * Determine the number of bytes of free disk space that are reserved according + * to the repo config and return that number in @out_reserved_bytes. See the + * documentation for the core.min-free-space-size and + * core.min-free-space-percent repo config options. + * + * Returns: %TRUE on success, %FALSE otherwise. + * Since: 2018.9 + */ +gboolean +ostree_repo_get_min_free_space_bytes (OstreeRepo *self, guint64 *out_reserved_bytes, GError **error) +{ + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); + g_return_val_if_fail (out_reserved_bytes != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (!min_free_space_calculate_reserved_bytes (self, out_reserved_bytes, error)) + return glnx_prefix_error (error, "Error calculating min-free-space bytes"); + + return TRUE; +} + +/** + * ostree_repo_get_parent: + * @self: Repo + * + * Before this function can be used, ostree_repo_init() must have been + * called. + * + * Returns: (transfer none): Parent repository, or %NULL if none + */ +OstreeRepo * +ostree_repo_get_parent (OstreeRepo *self) +{ + return self->parent_repo; +} + +static gboolean +list_loose_objects_at (OstreeRepo *self, + GHashTable *inout_objects, + int dfd, + const char *prefix, + const char *commit_starting_with, + GCancellable *cancellable, + GError **error) +{ + GVariant *key, *value; + + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (dfd, prefix, &dfd_iter, &exists, error)) + return FALSE; + /* Note early return */ + if (!exists) + return TRUE; + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + const char *name = dent->d_name; + if (strcmp (name, ".") == 0 || + strcmp (name, "..") == 0) + continue; + + const char *dot = strrchr (name, '.'); + if (!dot) + continue; + + OstreeObjectType objtype; + if ((self->mode == OSTREE_REPO_MODE_ARCHIVE + && strcmp (dot, ".filez") == 0) || + ((_ostree_repo_mode_is_bare (self->mode)) + && strcmp (dot, ".file") == 0)) + objtype = OSTREE_OBJECT_TYPE_FILE; + else if (strcmp (dot, ".dirtree") == 0) + objtype = OSTREE_OBJECT_TYPE_DIR_TREE; + else if (strcmp (dot, ".dirmeta") == 0) + objtype = OSTREE_OBJECT_TYPE_DIR_META; + else if (strcmp (dot, ".commit") == 0) + objtype = OSTREE_OBJECT_TYPE_COMMIT; + else if (strcmp (dot, ".payload-link") == 0) + objtype = OSTREE_OBJECT_TYPE_PAYLOAD_LINK; + else + continue; + + if ((dot - name) != 62) + continue; + + char buf[OSTREE_SHA256_STRING_LEN+1]; + + memcpy (buf, prefix, 2); + memcpy (buf + 2, name, 62); + buf[sizeof(buf)-1] = '\0'; + + /* if we passed in a "starting with" argument, then + we only want to return .commit objects with a checksum + that matches the commit_starting_with argument */ + if (commit_starting_with) + { + /* object is not a commit, do not add to array */ + if (objtype != OSTREE_OBJECT_TYPE_COMMIT) + continue; + + /* commit checksum does not match "starting with", do not add to array */ + if (!g_str_has_prefix (buf, commit_starting_with)) + continue; + } + + key = ostree_object_name_serialize (buf, objtype); + value = g_variant_new ("(b@as)", + TRUE, g_variant_new_strv (NULL, 0)); + /* transfer ownership */ + g_hash_table_replace (inout_objects, g_variant_ref_sink (key), + g_variant_ref_sink (value)); + } + + return TRUE; +} + +static gboolean +list_loose_objects (OstreeRepo *self, + GHashTable *inout_objects, + const char *commit_starting_with, + GCancellable *cancellable, + GError **error) +{ + static const gchar hexchars[] = "0123456789abcdef"; + + for (guint c = 0; c < 256; c++) + { + char buf[3]; + buf[0] = hexchars[c >> 4]; + buf[1] = hexchars[c & 0xF]; + buf[2] = '\0'; + if (!list_loose_objects_at (self, inout_objects, self->objects_dir_fd, buf, + commit_starting_with, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +load_metadata_internal (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + gboolean error_if_not_found, + GVariant **out_variant, + GInputStream **out_stream, + guint64 *out_size, + OstreeRepoCommitState *out_state, + GCancellable *cancellable, + GError **error) +{ + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + glnx_autofd int fd = -1; + g_autoptr(GInputStream) ret_stream = NULL; + g_autoptr(GVariant) ret_variant = NULL; + + g_return_val_if_fail (OSTREE_OBJECT_TYPE_IS_META (objtype), FALSE); + g_return_val_if_fail (objtype == OSTREE_OBJECT_TYPE_COMMIT || out_state == NULL, FALSE); + + /* Special caching for dirmeta objects, since they're commonly referenced many + * times. + */ + const gboolean is_dirmeta_cachable = + (objtype == OSTREE_OBJECT_TYPE_DIR_META && out_variant && !out_stream); + if (is_dirmeta_cachable) + { + GMutex *lock = &self->cache_lock; + g_mutex_lock (lock); + GVariant *cache_hit = NULL; + /* Look it up, if we have a cache */ + if (self->dirmeta_cache) + cache_hit = g_hash_table_lookup (self->dirmeta_cache, sha256); + if (cache_hit) + *out_variant = g_variant_ref (cache_hit); + g_mutex_unlock (lock); + if (cache_hit) + return TRUE; + } + + _ostree_loose_path (loose_path_buf, sha256, objtype, self->mode); + + if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, &fd, + error)) + return FALSE; + + if (fd < 0 && self->commit_stagedir.initialized) + { + if (!ot_openat_ignore_enoent (self->commit_stagedir.fd, loose_path_buf, &fd, + error)) + return FALSE; + } + + if (fd != -1) + { + struct stat stbuf; + if (!glnx_fstat (fd, &stbuf, error)) + return FALSE; + if (out_variant) + { + if (!ot_variant_read_fd (fd, 0, ostree_metadata_variant_type (objtype), TRUE, + &ret_variant, error)) + return FALSE; + + /* Now, let's put it in the cache */ + if (is_dirmeta_cachable) + { + GMutex *lock = &self->cache_lock; + g_mutex_lock (lock); + if (self->dirmeta_cache) + g_hash_table_replace (self->dirmeta_cache, g_strdup (sha256), g_variant_ref (ret_variant)); + g_mutex_unlock (lock); + } + } + else if (out_stream) + { + ret_stream = g_unix_input_stream_new (fd, TRUE); + if (!ret_stream) + return FALSE; + fd = -1; /* Transfer ownership */ + } + + if (out_size) + *out_size = stbuf.st_size; + + if (out_state) + { + g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (sha256); + *out_state = 0; + + glnx_autofd int fd = -1; + if (!ot_openat_ignore_enoent (self->repo_dir_fd, commitpartial_path, &fd, error)) + return FALSE; + if (fd != -1) + { + *out_state |= OSTREE_REPO_COMMIT_STATE_PARTIAL; + char reason; + if (read (fd, &reason, 1) == 1) + { + if (reason == 'f') + *out_state |= OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL; + } + } + } + } + else if (self->parent_repo) + { + /* Directly recurse to simplify out parameters */ + return load_metadata_internal (self->parent_repo, objtype, sha256, error_if_not_found, + out_variant, out_stream, out_size, out_state, + cancellable, error); + } + else if (error_if_not_found) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No such metadata object %s.%s", + sha256, ostree_object_type_to_string (objtype)); + return FALSE; + } + + ot_transfer_out_value (out_variant, &ret_variant); + ot_transfer_out_value (out_stream, &ret_stream); + return TRUE; +} + +static GVariant * +filemeta_to_stat (struct stat *stbuf, + GVariant *metadata) +{ + guint32 uid, gid, mode; + GVariant *xattrs; + + g_variant_get (metadata, "(uuu@a(ayay))", + &uid, &gid, &mode, &xattrs); + stbuf->st_uid = GUINT32_FROM_BE (uid); + stbuf->st_gid = GUINT32_FROM_BE (gid); + stbuf->st_mode = GUINT32_FROM_BE (mode); + + return xattrs; +} + +static gboolean +repo_load_file_archive (OstreeRepo *self, + const char *checksum, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + struct stat stbuf; + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, self->mode); + + glnx_autofd int fd = -1; + if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, &fd, + error)) + return FALSE; + + if (fd < 0 && self->commit_stagedir.initialized) + { + if (!ot_openat_ignore_enoent (self->commit_stagedir.fd, loose_path_buf, &fd, + error)) + return FALSE; + } + + if (fd != -1) + { + if (!glnx_fstat (fd, &stbuf, error)) + return FALSE; + + g_autoptr(GInputStream) tmp_stream = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE); + /* Note return here */ + return ostree_content_stream_parse (TRUE, tmp_stream, stbuf.st_size, TRUE, + out_input, out_file_info, out_xattrs, + cancellable, error); + } + else if (self->parent_repo) + { + return ostree_repo_load_file (self->parent_repo, checksum, + out_input, out_file_info, out_xattrs, + cancellable, error); + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Couldn't find file object '%s'", checksum); + return FALSE; + } +} + +gboolean +_ostree_repo_load_file_bare (OstreeRepo *self, + const char *checksum, + int *out_fd, + struct stat *out_stbuf, + char **out_symlink, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + /* The bottom case recursing on the parent repo */ + if (self == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Couldn't find file object '%s'", checksum); + return FALSE; + } + + const char *errprefix = glnx_strjoina ("Opening content object ", checksum); + GLNX_AUTO_PREFIX_ERROR (errprefix, error); + + struct stat stbuf; + glnx_autofd int fd = -1; + g_autofree char *ret_symlink = NULL; + g_autoptr(GVariant) ret_xattrs = NULL; + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, self->mode); + + /* Do a fstatat() and find the object directory that contains this object */ + int objdir_fd = self->objects_dir_fd; + int res; + if ((res = TEMP_FAILURE_RETRY (fstatat (objdir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW))) < 0 + && errno == ENOENT && self->commit_stagedir.initialized) + { + objdir_fd = self->commit_stagedir.fd; + res = TEMP_FAILURE_RETRY (fstatat (objdir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW)); + } + if (res < 0 && errno != ENOENT) + return glnx_throw_errno_prefix (error, "fstat"); + else if (res < 0) + { + g_assert (errno == ENOENT); + return _ostree_repo_load_file_bare (self->parent_repo, checksum, out_fd, + out_stbuf, out_symlink, out_xattrs, + cancellable, error); + } + + const gboolean need_open = + (out_fd || out_xattrs || self->mode == OSTREE_REPO_MODE_BARE_USER); + /* If it's a regular file and we're requested to return the fd, do it now. As + * a special case in bare-user, we always do an open, since the stat() metadata + * lives there. + */ + if (need_open && S_ISREG (stbuf.st_mode)) + { + fd = openat (objdir_fd, loose_path_buf, O_CLOEXEC | O_RDONLY); + if (fd < 0) + return glnx_throw_errno_prefix (error, "openat"); + } + + if (!(S_ISREG (stbuf.st_mode) || S_ISLNK (stbuf.st_mode))) + return glnx_throw (error, "Not a regular file or symlink"); + + /* In the non-bare-user case, gather symlink info if requested */ + if (self->mode != OSTREE_REPO_MODE_BARE_USER + && S_ISLNK (stbuf.st_mode) && out_symlink) + { + ret_symlink = glnx_readlinkat_malloc (objdir_fd, loose_path_buf, + cancellable, error); + if (!ret_symlink) + return FALSE; + } + + if (self->mode == OSTREE_REPO_MODE_BARE_USER) + { + g_autoptr(GBytes) bytes = glnx_fgetxattr_bytes (fd, "user.ostreemeta", error); + if (bytes == NULL) + return FALSE; + + g_autoptr(GVariant) metadata = g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_FILEMETA_GVARIANT_FORMAT, + bytes, FALSE)); + ret_xattrs = filemeta_to_stat (&stbuf, metadata); + if (S_ISLNK (stbuf.st_mode)) + { + if (out_symlink) + { + char targetbuf[PATH_MAX+1]; + gsize target_size; + g_autoptr(GInputStream) target_input = g_unix_input_stream_new (fd, FALSE); + if (!g_input_stream_read_all (target_input, targetbuf, sizeof (targetbuf), + &target_size, cancellable, error)) + return FALSE; + + ret_symlink = g_strndup (targetbuf, target_size); + } + /* In the symlink case, we don't want to return the bare-user fd */ + glnx_close_fd (&fd); + } + } + else if (self->mode == OSTREE_REPO_MODE_BARE_USER_ONLY) + { + /* Canonical info is: uid/gid is 0 and no xattrs, which + might be wrong and thus not validate correctly, but + at least we report something consistent. */ + stbuf.st_uid = stbuf.st_gid = 0; + + if (out_xattrs) + { + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)")); + ret_xattrs = g_variant_ref_sink (g_variant_builder_end (&builder)); + } + } + else + { + g_assert (self->mode == OSTREE_REPO_MODE_BARE); + + if (S_ISREG (stbuf.st_mode) && out_xattrs) + { + if (self->disable_xattrs) + ret_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); + else if (!glnx_fd_get_all_xattrs (fd, &ret_xattrs, + cancellable, error)) + return FALSE; + } + else if (S_ISLNK (stbuf.st_mode) && out_xattrs) + { + if (self->disable_xattrs) + ret_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); + else if (!glnx_dfd_name_get_all_xattrs (objdir_fd, loose_path_buf, + &ret_xattrs, + cancellable, error)) + return FALSE; + } + } + + if (out_fd) + *out_fd = glnx_steal_fd (&fd); + if (out_stbuf) + *out_stbuf = stbuf; + ot_transfer_out_value (out_symlink, &ret_symlink); + ot_transfer_out_value (out_xattrs, &ret_xattrs); + return TRUE; +} + +/** + * ostree_repo_load_file: + * @self: Repo + * @checksum: ASCII SHA256 checksum + * @out_input: (out) (optional) (nullable): File content + * @out_file_info: (out) (optional) (nullable): File information + * @out_xattrs: (out) (optional) (nullable): Extended attributes + * @cancellable: Cancellable + * @error: Error + * + * Load content object, decomposing it into three parts: the actual + * content (for regular files), the metadata, and extended attributes. + */ +gboolean +ostree_repo_load_file (OstreeRepo *self, + const char *checksum, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error) +{ + if (self->mode == OSTREE_REPO_MODE_ARCHIVE) + return repo_load_file_archive (self, checksum, out_input, out_file_info, out_xattrs, + cancellable, error); + else + { + glnx_autofd int fd = -1; + struct stat stbuf; + g_autofree char *symlink_target = NULL; + g_autoptr(GVariant) ret_xattrs = NULL; + if (!_ostree_repo_load_file_bare (self, checksum, + out_input ? &fd : NULL, + out_file_info ? &stbuf : NULL, + out_file_info ? &symlink_target : NULL, + out_xattrs ? &ret_xattrs : NULL, + cancellable, error)) + return FALSE; + + /* Convert fd → GInputStream and struct stat → GFileInfo */ + if (out_input) + { + if (fd != -1) + *out_input = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE); + else + *out_input = NULL; + } + if (out_file_info) + { + *out_file_info = _ostree_stbuf_to_gfileinfo (&stbuf); + if (S_ISLNK (stbuf.st_mode)) + g_file_info_set_symlink_target (*out_file_info, symlink_target); + else + g_assert (S_ISREG (stbuf.st_mode)); + } + + ot_transfer_out_value (out_xattrs, &ret_xattrs); + return TRUE; + } +} + +/** + * ostree_repo_load_object_stream: + * @self: Repo + * @objtype: Object type + * @checksum: ASCII SHA256 checksum + * @out_input: (out): Stream for object + * @out_size: (out): Length of @out_input + * @cancellable: Cancellable + * @error: Error + * + * Load object as a stream; useful when copying objects between + * repositories. + */ +gboolean +ostree_repo_load_object_stream (OstreeRepo *self, + OstreeObjectType objtype, + const char *checksum, + GInputStream **out_input, + guint64 *out_size, + GCancellable *cancellable, + GError **error) +{ + guint64 size; + g_autoptr(GInputStream) ret_input = NULL; + + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + { + if (!load_metadata_internal (self, objtype, checksum, TRUE, NULL, + &ret_input, &size, NULL, + cancellable, error)) + return FALSE; + } + else + { + g_autoptr(GInputStream) input = NULL; + g_autoptr(GFileInfo) finfo = NULL; + g_autoptr(GVariant) xattrs = NULL; + + if (!ostree_repo_load_file (self, checksum, &input, &finfo, &xattrs, + cancellable, error)) + return FALSE; + + if (!ostree_raw_file_to_content_stream (input, finfo, xattrs, + &ret_input, &size, + cancellable, error)) + return FALSE; + } + + ot_transfer_out_value (out_input, &ret_input); + *out_size = size; + return TRUE; +} + +/* + * _ostree_repo_has_loose_object: + * @loose_path_buf: Buffer of size _OSTREE_LOOSE_PATH_MAX + * + * Locate object in repository; if it exists, @out_is_stored will be + * set to TRUE. @loose_path_buf is always set to the loose path. + */ +gboolean +_ostree_repo_has_loose_object (OstreeRepo *self, + const char *checksum, + OstreeObjectType objtype, + gboolean *out_is_stored, + GCancellable *cancellable, + GError **error) +{ + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (loose_path_buf, checksum, objtype, self->mode); + + gboolean found = FALSE; + /* It's easier to share code if we make this an array */ + int dfd_searches[] = { -1, self->objects_dir_fd }; + if (self->commit_stagedir.initialized) + dfd_searches[0] = self->commit_stagedir.fd; + for (guint i = 0; i < G_N_ELEMENTS (dfd_searches); i++) + { + int dfd = dfd_searches[i]; + if (dfd == -1) + continue; + struct stat stbuf; + if (TEMP_FAILURE_RETRY (fstatat (dfd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW)) < 0) + { + if (errno == ENOENT) + ; /* Next dfd */ + else + return glnx_throw_errno_prefix (error, "fstatat(%s)", loose_path_buf); + } + else + { + found = TRUE; + break; + } + } + + *out_is_stored = found; + return TRUE; +} + +/** + * ostree_repo_has_object: + * @self: Repo + * @objtype: Object type + * @checksum: ASCII SHA256 checksum + * @out_have_object: (out): %TRUE if repository contains object + * @cancellable: Cancellable + * @error: Error + * + * Set @out_have_object to %TRUE if @self contains the given object; + * %FALSE otherwise. + * + * Returns: %FALSE if an unexpected error occurred, %TRUE otherwise + */ +gboolean +ostree_repo_has_object (OstreeRepo *self, + OstreeObjectType objtype, + const char *checksum, + gboolean *out_have_object, + GCancellable *cancellable, + GError **error) +{ + gboolean ret_have_object = FALSE; + + if (!_ostree_repo_has_loose_object (self, checksum, objtype, &ret_have_object, + cancellable, error)) + return FALSE; + + /* In the future, here is where we would also look up in metadata pack files */ + + if (!ret_have_object && self->parent_repo) + { + if (!ostree_repo_has_object (self->parent_repo, objtype, checksum, + &ret_have_object, cancellable, error)) + return FALSE; + } + + if (out_have_object) + *out_have_object = ret_have_object; + return TRUE; +} + +/** + * ostree_repo_delete_object: + * @self: Repo + * @objtype: Object type + * @sha256: Checksum + * @cancellable: Cancellable + * @error: Error + * + * Remove the object of type @objtype with checksum @sha256 + * from the repository. An error of type %G_IO_ERROR_NOT_FOUND + * is thrown if the object does not exist. + */ +gboolean +ostree_repo_delete_object (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + GCancellable *cancellable, + GError **error) +{ + char loose_path[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (loose_path, sha256, objtype, self->mode); + + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + char meta_loose[_OSTREE_LOOSE_PATH_MAX]; + + _ostree_loose_path (meta_loose, sha256, OSTREE_OBJECT_TYPE_COMMIT_META, self->mode); + + if (!ot_ensure_unlinked_at (self->objects_dir_fd, meta_loose, error)) + return FALSE; + } + + if (!glnx_unlinkat (self->objects_dir_fd, loose_path, 0, error)) + return glnx_prefix_error (error, "Deleting object %s.%s", sha256, ostree_object_type_to_string (objtype)); + + /* If the repository is configured to use tombstone commits, create one when deleting a commit. */ + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + gboolean tombstone_commits = FALSE; + GKeyFile *readonly_config = ostree_repo_get_config (self); + if (!ot_keyfile_get_boolean_with_default (readonly_config, "core", "tombstone-commits", FALSE, + &tombstone_commits, error)) + return FALSE; + + if (tombstone_commits) + { + g_auto(GVariantBuilder) builder = OT_VARIANT_BUILDER_INITIALIZER; + g_autoptr(GVariant) variant = NULL; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&builder, "{sv}", "commit", g_variant_new_bytestring (sha256)); + variant = g_variant_ref_sink (g_variant_builder_end (&builder)); + if (!ostree_repo_write_metadata_trusted (self, + OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT, + sha256, + variant, + cancellable, + error)) + return FALSE; + } + } + + return TRUE; +} + +/* Thin wrapper for _ostree_verify_metadata_object() */ +static gboolean +fsck_metadata_object (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + GCancellable *cancellable, + GError **error) +{ + const char *errmsg = glnx_strjoina ("fsck ", sha256, ".", ostree_object_type_to_string (objtype)); + GLNX_AUTO_PREFIX_ERROR (errmsg, error); + g_autoptr(GVariant) metadata = NULL; + if (!load_metadata_internal (self, objtype, sha256, TRUE, + &metadata, NULL, NULL, NULL, + cancellable, error)) + return FALSE; + + return _ostree_verify_metadata_object (objtype, sha256, metadata, error); +} + +static gboolean +fsck_content_object (OstreeRepo *self, + const char *sha256, + GCancellable *cancellable, + GError **error) +{ + const char *errmsg = glnx_strjoina ("fsck content object ", sha256); + GLNX_AUTO_PREFIX_ERROR (errmsg, error); + g_autoptr(GInputStream) input = NULL; + g_autoptr(GFileInfo) file_info = NULL; + g_autoptr(GVariant) xattrs = NULL; + + if (!ostree_repo_load_file (self, sha256, &input, &file_info, &xattrs, + cancellable, error)) + return FALSE; + + /* TODO more consistency checks here */ + const guint32 mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + if (!ostree_validate_structureof_file_mode (mode, error)) + return FALSE; + + g_autofree guchar *computed_csum = NULL; + if (!ostree_checksum_file_from_input (file_info, xattrs, input, + OSTREE_OBJECT_TYPE_FILE, &computed_csum, + cancellable, error)) + return FALSE; + + char actual_checksum[OSTREE_SHA256_STRING_LEN+1]; + ostree_checksum_inplace_from_bytes (computed_csum, actual_checksum); + return _ostree_compare_object_checksum (OSTREE_OBJECT_TYPE_FILE, sha256, actual_checksum, error); +} + +/** + * ostree_repo_fsck_object: + * @self: Repo + * @objtype: Object type + * @sha256: Checksum + * @cancellable: Cancellable + * @error: Error + * + * Verify consistency of the object; this performs checks only relevant to the + * immediate object itself, such as checksumming. This API call will not itself + * traverse metadata objects for example. + * + * Since: 2017.15 + */ +gboolean +ostree_repo_fsck_object (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + GCancellable *cancellable, + GError **error) +{ + if (OSTREE_OBJECT_TYPE_IS_META (objtype)) + return fsck_metadata_object (self, objtype, sha256, cancellable, error); + else + return fsck_content_object (self, sha256, cancellable, error); +} + +/** + * ostree_repo_import_object_from: + * @self: Destination repo + * @source: Source repo + * @objtype: Object type + * @checksum: checksum + * @cancellable: Cancellable + * @error: Error + * + * Copy object named by @objtype and @checksum into @self from the + * source repository @source. If both repositories are of the same + * type and on the same filesystem, this will simply be a fast Unix + * hard link operation. + * + * Otherwise, a copy will be performed. + */ +gboolean +ostree_repo_import_object_from (OstreeRepo *self, + OstreeRepo *source, + OstreeObjectType objtype, + const char *checksum, + GCancellable *cancellable, + GError **error) +{ + return + ostree_repo_import_object_from_with_trust (self, source, objtype, + checksum, TRUE, cancellable, error); +} + +/** + * ostree_repo_import_object_from_with_trust: + * @self: Destination repo + * @source: Source repo + * @objtype: Object type + * @checksum: checksum + * @trusted: If %TRUE, assume the source repo is valid and trusted + * @cancellable: Cancellable + * @error: Error + * + * Copy object named by @objtype and @checksum into @self from the + * source repository @source. If @trusted is %TRUE and both + * repositories are of the same type and on the same filesystem, + * this will simply be a fast Unix hard link operation. + * + * Otherwise, a copy will be performed. + * + * Since: 2016.5 + */ +gboolean +ostree_repo_import_object_from_with_trust (OstreeRepo *self, + OstreeRepo *source, + OstreeObjectType objtype, + const char *checksum, + gboolean trusted, + GCancellable *cancellable, + GError **error) +{ + /* This just wraps a currently internal API, may make it public later */ + OstreeRepoImportFlags flags = trusted ? _OSTREE_REPO_IMPORT_FLAGS_TRUSTED : 0; + return _ostree_repo_import_object (self, source, objtype, checksum, + flags, cancellable, error); +} + +/** + * ostree_repo_query_object_storage_size: + * @self: Repo + * @objtype: Object type + * @sha256: Checksum + * @out_size: (out): Size in bytes object occupies physically + * @cancellable: Cancellable + * @error: Error + * + * Return the size in bytes of object with checksum @sha256, after any + * compression has been applied. + */ +gboolean +ostree_repo_query_object_storage_size (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + guint64 *out_size, + GCancellable *cancellable, + GError **error) +{ + char loose_path[_OSTREE_LOOSE_PATH_MAX]; + _ostree_loose_path (loose_path, sha256, objtype, self->mode); + int res; + + struct stat stbuf; + res = TEMP_FAILURE_RETRY (fstatat (self->objects_dir_fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW)); + if (res < 0 && errno == ENOENT && self->commit_stagedir.initialized) + res = TEMP_FAILURE_RETRY (fstatat (self->commit_stagedir.fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW)); + + if (res < 0) + return glnx_throw_errno_prefix (error, "Querying object %s.%s", sha256, ostree_object_type_to_string (objtype)); + + *out_size = stbuf.st_size; + return TRUE; +} + +/** + * ostree_repo_load_variant_if_exists: + * @self: Repo + * @objtype: Object type + * @sha256: ASCII checksum + * @out_variant: (out) (transfer full): Metadata + * @error: Error + * + * Attempt to load the metadata object @sha256 of type @objtype if it + * exists, storing the result in @out_variant. If it doesn't exist, + * %NULL is returned. + */ +gboolean +ostree_repo_load_variant_if_exists (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + GVariant **out_variant, + GError **error) +{ + return load_metadata_internal (self, objtype, sha256, FALSE, + out_variant, NULL, NULL, NULL, NULL, error); +} + +/** + * ostree_repo_load_variant: + * @self: Repo + * @objtype: Expected object type + * @sha256: Checksum string + * @out_variant: (out) (transfer full): Metadata object + * @error: Error + * + * Load the metadata object @sha256 of type @objtype, storing the + * result in @out_variant. + */ +gboolean +ostree_repo_load_variant (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + GVariant **out_variant, + GError **error) +{ + return load_metadata_internal (self, objtype, sha256, TRUE, + out_variant, NULL, NULL, NULL, NULL, error); +} + +/** + * ostree_repo_load_commit: + * @self: Repo + * @checksum: Commit checksum + * @out_commit: (out) (allow-none): Commit + * @out_state: (out) (allow-none): Commit state + * @error: Error + * + * A version of ostree_repo_load_variant() specialized to commits, + * capable of returning extended state information. Currently + * the only extended state is %OSTREE_REPO_COMMIT_STATE_PARTIAL, which + * means that only a sub-path of the commit is available. + */ +gboolean +ostree_repo_load_commit (OstreeRepo *self, + const char *checksum, + GVariant **out_variant, + OstreeRepoCommitState *out_state, + GError **error) +{ + return load_metadata_internal (self, OSTREE_OBJECT_TYPE_COMMIT, checksum, TRUE, + out_variant, NULL, NULL, out_state, NULL, error); +} + +/** + * ostree_repo_list_objects: + * @self: Repo + * @flags: Flags controlling enumeration + * @out_objects: (out) (transfer container) (element-type GVariant GVariant): + * Map of serialized object name to variant data + * @cancellable: Cancellable + * @error: Error + * + * This function synchronously enumerates all objects in the + * repository, returning data in @out_objects. @out_objects + * maps from keys returned by ostree_object_name_serialize() + * to #GVariant values of type %OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE. + * + * Returns: %TRUE on success, %FALSE on error, and @error will be set + */ +gboolean +ostree_repo_list_objects (OstreeRepo *self, + OstreeRepoListObjectsFlags flags, + GHashTable **out_objects, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (self->inited, FALSE); + + g_autoptr(GHashTable) ret_objects = + g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, + (GDestroyNotify) g_variant_unref, + (GDestroyNotify) g_variant_unref); + + if (flags & OSTREE_REPO_LIST_OBJECTS_ALL) + flags |= (OSTREE_REPO_LIST_OBJECTS_LOOSE | OSTREE_REPO_LIST_OBJECTS_PACKED); + + if (flags & OSTREE_REPO_LIST_OBJECTS_LOOSE) + { + if (!list_loose_objects (self, ret_objects, NULL, cancellable, error)) + return FALSE; + if ((flags & OSTREE_REPO_LIST_OBJECTS_NO_PARENTS) == 0 && self->parent_repo) + { + if (!list_loose_objects (self->parent_repo, ret_objects, NULL, cancellable, error)) + return FALSE; + } + } + + if (flags & OSTREE_REPO_LIST_OBJECTS_PACKED) + { + /* Nothing for now... */ + } + + ot_transfer_out_value (out_objects, &ret_objects); + return TRUE; +} + +/** + * ostree_repo_list_commit_objects_starting_with: + * @self: Repo + * @start: List commits starting with this checksum + * @out_commits: (out) (transfer container) (element-type GVariant GVariant): + * Map of serialized commit name to variant data + * @cancellable: Cancellable + * @error: Error + * + * This function synchronously enumerates all commit objects starting + * with @start, returning data in @out_commits. + * + * Returns: %TRUE on success, %FALSE on error, and @error will be set + */ +gboolean +ostree_repo_list_commit_objects_starting_with (OstreeRepo *self, + const char *start, + GHashTable **out_commits, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (self->inited, FALSE); + + g_autoptr(GHashTable) ret_commits = + g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, + (GDestroyNotify) g_variant_unref, + (GDestroyNotify) g_variant_unref); + + if (!list_loose_objects (self, ret_commits, start, cancellable, error)) + return FALSE; + + if (self->parent_repo) + { + if (!list_loose_objects (self->parent_repo, ret_commits, start, + cancellable, error)) + return FALSE; + } + + ot_transfer_out_value (out_commits, &ret_commits); + return TRUE; +} + +/** + * ostree_repo_read_commit: + * @self: Repo + * @ref: Ref or ASCII checksum + * @out_root: (out): An #OstreeRepoFile corresponding to the root + * @out_commit: (out): The resolved commit checksum + * @cancellable: Cancellable + * @error: Error + * + * Load the content for @rev into @out_root. + */ +gboolean +ostree_repo_read_commit (OstreeRepo *self, + const char *ref, + GFile **out_root, + char **out_commit, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *resolved_commit = NULL; + if (!ostree_repo_resolve_rev (self, ref, FALSE, &resolved_commit, error)) + return FALSE; + + g_autoptr(GFile) ret_root = (GFile*) _ostree_repo_file_new_for_commit (self, resolved_commit, error); + if (!ret_root) + return FALSE; + + if (!ostree_repo_file_ensure_resolved ((OstreeRepoFile*)ret_root, error)) + return FALSE; + + ot_transfer_out_value(out_root, &ret_root); + ot_transfer_out_value(out_commit, &resolved_commit); + return TRUE; +} + +/** + * ostree_repo_pull: + * @self: Repo + * @remote_name: Name of remote + * @refs_to_fetch: (array zero-terminated=1) (element-type utf8) (allow-none): Optional list of refs; if %NULL, fetch all configured refs + * @flags: Options controlling fetch behavior + * @progress: (allow-none): Progress + * @cancellable: Cancellable + * @error: Error + * + * Connect to the remote repository, fetching the specified set of + * refs @refs_to_fetch. For each ref that is changed, download the + * commit, all metadata, and all content objects, storing them safely + * on disk in @self. + * + * If @flags contains %OSTREE_REPO_PULL_FLAGS_MIRROR, and + * the @refs_to_fetch is %NULL, and the remote repository contains a + * summary file, then all refs will be fetched. + * + * If @flags contains %OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY, then only the + * metadata for the commits in @refs_to_fetch is pulled. + * + * Warning: This API will iterate the thread default main context, + * which is a bug, but kept for compatibility reasons. If you want to + * avoid this, use g_main_context_push_thread_default() to push a new + * one around this call. + */ +gboolean +ostree_repo_pull (OstreeRepo *self, + const char *remote_name, + char **refs_to_fetch, + OstreeRepoPullFlags flags, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GError **error) +{ + return ostree_repo_pull_one_dir (self, remote_name, NULL, refs_to_fetch, flags, progress, cancellable, error); +} + +/** + * ostree_repo_pull_one_dir: + * @self: Repo + * @remote_name: Name of remote + * @dir_to_pull: Subdirectory path + * @refs_to_fetch: (array zero-terminated=1) (element-type utf8) (allow-none): Optional list of refs; if %NULL, fetch all configured refs + * @flags: Options controlling fetch behavior + * @progress: (allow-none): Progress + * @cancellable: Cancellable + * @error: Error + * + * This is similar to ostree_repo_pull(), but only fetches a single + * subpath. + */ +gboolean +ostree_repo_pull_one_dir (OstreeRepo *self, + const char *remote_name, + const char *dir_to_pull, + char **refs_to_fetch, + OstreeRepoPullFlags flags, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GError **error) +{ + GVariantBuilder builder; + g_autoptr(GVariant) options = NULL; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + if (dir_to_pull) + g_variant_builder_add (&builder, "{s@v}", "subdir", + g_variant_new_variant (g_variant_new_string (dir_to_pull))); + g_variant_builder_add (&builder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (flags))); + if (refs_to_fetch) + g_variant_builder_add (&builder, "{s@v}", "refs", + g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch, -1))); + + options = g_variant_ref_sink (g_variant_builder_end (&builder)); + return ostree_repo_pull_with_options (self, remote_name, options, + progress, cancellable, error); +} + +/** + * _formatted_time_remaining_from_seconds + * @seconds_remaining: Estimated number of seconds remaining. + * + * Returns a strings showing the number of days, hours, minutes + * and seconds remaining. + **/ +static char * +_formatted_time_remaining_from_seconds (guint64 seconds_remaining) +{ + guint64 minutes_remaining = seconds_remaining / 60; + guint64 hours_remaining = minutes_remaining / 60; + guint64 days_remaining = hours_remaining / 24; + + GString *description = g_string_new (NULL); + + if (days_remaining) + g_string_append_printf (description, "%" G_GUINT64_FORMAT " days ", days_remaining); + + if (hours_remaining) + g_string_append_printf (description, "%" G_GUINT64_FORMAT " hours ", hours_remaining % 24); + + if (minutes_remaining) + g_string_append_printf (description, "%" G_GUINT64_FORMAT " minutes ", minutes_remaining % 60); + + g_string_append_printf (description, "%" G_GUINT64_FORMAT " seconds ", seconds_remaining % 60); + + return g_string_free (description, FALSE); +} + +/** + * ostree_repo_pull_default_console_progress_changed: + * @progress: Async progress + * @user_data: (allow-none): User data + * + * Convenient "changed" callback for use with + * ostree_async_progress_new_and_connect() when pulling from a remote + * repository. + * + * Depending on the state of the #OstreeAsyncProgress, either displays a + * custom status message, or else outstanding fetch progress in bytes/sec, + * or else outstanding content or metadata writes to the repository in + * number of objects. + * + * Compatibility note: this function previously assumed that @user_data + * was a pointer to a #GSConsole instance. This is no longer the case, + * and @user_data is ignored. + **/ +void +ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress, + gpointer user_data) +{ + g_autofree char *status = NULL; + gboolean caught_error, scanning; + guint outstanding_fetches; + guint outstanding_metadata_fetches; + guint outstanding_writes; + guint n_scanned_metadata; + guint fetched_delta_parts; + guint total_delta_parts; + guint fetched_delta_part_fallbacks; + guint total_delta_part_fallbacks; + + g_autoptr(GString) buf = g_string_new (""); + + ostree_async_progress_get (progress, + "outstanding-fetches", "u", &outstanding_fetches, + "outstanding-metadata-fetches", "u", &outstanding_metadata_fetches, + "outstanding-writes", "u", &outstanding_writes, + "caught-error", "b", &caught_error, + "scanning", "u", &scanning, + "scanned-metadata", "u", &n_scanned_metadata, + "fetched-delta-parts", "u", &fetched_delta_parts, + "total-delta-parts", "u", &total_delta_parts, + "fetched-delta-fallbacks", "u", &fetched_delta_part_fallbacks, + "total-delta-fallbacks", "u", &total_delta_part_fallbacks, + "status", "s", &status, + NULL); + + if (*status != '\0') + { + g_string_append (buf, status); + } + else if (caught_error) + { + g_string_append_printf (buf, "Caught error, waiting for outstanding tasks"); + } + else if (outstanding_fetches) + { + guint64 bytes_transferred, start_time, total_delta_part_size; + guint fetched, metadata_fetched, requested; + guint64 current_time = g_get_monotonic_time (); + g_autofree char *formatted_bytes_transferred = NULL; + g_autofree char *formatted_bytes_sec = NULL; + guint64 bytes_sec; + + /* Note: This is not atomic wrt the above getter call. */ + ostree_async_progress_get (progress, + "bytes-transferred", "t", &bytes_transferred, + "fetched", "u", &fetched, + "metadata-fetched", "u", &metadata_fetched, + "requested", "u", &requested, + "start-time", "t", &start_time, + "total-delta-part-size", "t", &total_delta_part_size, + NULL); + + formatted_bytes_transferred = g_format_size_full (bytes_transferred, 0); + + /* Ignore the first second, or when we haven't transferred any + * data, since those could cause divide by zero below. + */ + if ((current_time - start_time) < G_USEC_PER_SEC || bytes_transferred == 0) + { + bytes_sec = 0; + formatted_bytes_sec = g_strdup ("-"); + } + else + { + bytes_sec = bytes_transferred / ((current_time - start_time) / G_USEC_PER_SEC); + formatted_bytes_sec = g_format_size (bytes_sec); + } + + /* Are we doing deltas? If so, we can be more accurate */ + if (total_delta_parts > 0) + { + guint64 fetched_delta_part_size = ostree_async_progress_get_uint64 (progress, "fetched-delta-part-size"); + g_autofree char *formatted_fetched = NULL; + g_autofree char *formatted_total = NULL; + + /* Here we merge together deltaparts + fallbacks to avoid bloating the text UI */ + fetched_delta_parts += fetched_delta_part_fallbacks; + total_delta_parts += total_delta_part_fallbacks; + + formatted_fetched = g_format_size (fetched_delta_part_size); + formatted_total = g_format_size (total_delta_part_size); + + if (bytes_sec > 0) + { + guint64 est_time_remaining = 0; + if (total_delta_part_size > fetched_delta_part_size) + est_time_remaining = (total_delta_part_size - fetched_delta_part_size) / bytes_sec; + g_autofree char *formatted_est_time_remaining = _formatted_time_remaining_from_seconds (est_time_remaining); + /* No space between %s and remaining, since formatted_est_time_remaining has a trailing space */ + g_string_append_printf (buf, "Receiving delta parts: %u/%u %s/%s %s/s %sremaining", + fetched_delta_parts, total_delta_parts, + formatted_fetched, formatted_total, + formatted_bytes_sec, + formatted_est_time_remaining); + } + else + { + g_string_append_printf (buf, "Receiving delta parts: %u/%u %s/%s", + fetched_delta_parts, total_delta_parts, + formatted_fetched, formatted_total); + } + } + else if (scanning || outstanding_metadata_fetches) + { + g_string_append_printf (buf, "Receiving metadata objects: %u/(estimating) %s/s %s", + metadata_fetched, formatted_bytes_sec, formatted_bytes_transferred); + } + else + { + g_string_append_printf (buf, "Receiving objects: %u%% (%u/%u) %s/s %s", + (guint)((((double)fetched) / requested) * 100), + fetched, requested, formatted_bytes_sec, formatted_bytes_transferred); + } + } + else if (outstanding_writes) + { + g_string_append_printf (buf, "Writing objects: %u", outstanding_writes); + } + else + { + g_string_append_printf (buf, "Scanning metadata: %u", n_scanned_metadata); + } + + glnx_console_text (buf->str); +} + +/** + * ostree_repo_append_gpg_signature: + * @self: Self + * @commit_checksum: SHA256 of given commit to sign + * @signature_bytes: Signature data + * @cancellable: A #GCancellable + * @error: a #GError + * + * Append a GPG signature to a commit. + */ +gboolean +ostree_repo_append_gpg_signature (OstreeRepo *self, + const gchar *commit_checksum, + GBytes *signature_bytes, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) metadata = NULL; + if (!ostree_repo_read_commit_detached_metadata (self, + commit_checksum, + &metadata, + cancellable, + error)) + return FALSE; + +#ifndef OSTREE_DISABLE_GPGME + g_autoptr(GVariant) new_metadata = + _ostree_detached_metadata_append_gpg_sig (metadata, signature_bytes); + + if (!ostree_repo_write_commit_detached_metadata (self, + commit_checksum, + new_metadata, + cancellable, + error)) + return FALSE; + + return TRUE; +#else + return glnx_throw (error, "GPG feature is disabled in a build time"); +#endif /* OSTREE_DISABLE_GPGME */ +} + +#ifndef OSTREE_DISABLE_GPGME +static gboolean +sign_data (OstreeRepo *self, + GBytes *input_data, + const gchar *key_id, + const gchar *homedir, + GBytes **out_signature, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (self->tmp_dir_fd, ".", O_RDWR | O_CLOEXEC, + &tmpf, error)) + return FALSE; + g_autoptr(GOutputStream) tmp_signature_output = g_unix_output_stream_new (tmpf.fd, FALSE); + + g_auto(gpgme_ctx_t) context = ot_gpgme_new_ctx (homedir, error); + if (!context) + return FALSE; + + /* Get the secret keys with the given key id */ + g_auto(gpgme_key_t) key = NULL; + gpgme_error_t err = gpgme_get_key (context, key_id, &key, 1); + if (gpgme_err_code (err) == GPG_ERR_EOF) + return glnx_throw (error, "No gpg key found with ID %s (homedir: %s)", key_id, + homedir ? homedir : ""); + else if (gpgme_err_code (err) == GPG_ERR_AMBIGUOUS_NAME) { + return glnx_throw (error, "gpg key id %s ambiguous (homedir: %s). Try the fingerprint instead", key_id, + homedir ? homedir : ""); + } + else if (err != GPG_ERR_NO_ERROR) + return ot_gpgme_throw (err, error, "Unable to lookup key ID %s", key_id); + + /* Add the key to the context as a signer */ + if ((err = gpgme_signers_add (context, key)) != GPG_ERR_NO_ERROR) + return ot_gpgme_throw (err, error, "Error signing commit"); + + /* Get a gpg buffer from the commit */ + g_auto(gpgme_data_t) commit_buffer = NULL; + gsize len; + const char *buf = g_bytes_get_data (input_data, &len); + if ((err = gpgme_data_new_from_mem (&commit_buffer, buf, len, FALSE)) != GPG_ERR_NO_ERROR) + return ot_gpgme_throw (err, error, "Failed to create buffer from commit file"); + + /* Sign it */ + g_auto(gpgme_data_t) signature_buffer = ot_gpgme_data_output (tmp_signature_output); + if ((err = gpgme_op_sign (context, commit_buffer, signature_buffer, GPGME_SIG_MODE_DETACH)) + != GPG_ERR_NO_ERROR) + return ot_gpgme_throw (err, error, "Failure signing commit file"); + if (!g_output_stream_close (tmp_signature_output, cancellable, error)) + return FALSE; + + /* Return a mmap() reference */ + g_autoptr(GMappedFile) signature_file = g_mapped_file_new_from_fd (tmpf.fd, FALSE, error); + if (!signature_file) + return FALSE; + + if (out_signature) + *out_signature = g_mapped_file_get_bytes (signature_file); + return TRUE; +} +#endif /* OSTREE_DISABLE_GPGME */ + +/** + * ostree_repo_sign_commit: + * @self: Self + * @commit_checksum: SHA256 of given commit to sign + * @key_id: Use this GPG key id + * @homedir: (allow-none): GPG home directory, or %NULL + * @cancellable: A #GCancellable + * @error: a #GError + * + * Add a GPG signature to a commit. + */ +gboolean +ostree_repo_sign_commit (OstreeRepo *self, + const gchar *commit_checksum, + const gchar *key_id, + const gchar *homedir, + GCancellable *cancellable, + GError **error) +{ +#ifndef OSTREE_DISABLE_GPGME + g_autoptr(GBytes) commit_data = NULL; + g_autoptr(GBytes) signature = NULL; + + g_autoptr(GVariant) commit_variant = NULL; + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, + commit_checksum, &commit_variant, error)) + return glnx_prefix_error (error, "Failed to read commit"); + + g_autoptr(GVariant) old_metadata = NULL; + if (!ostree_repo_read_commit_detached_metadata (self, + commit_checksum, + &old_metadata, + cancellable, + error)) + return glnx_prefix_error (error, "Failed to read detached metadata"); + + commit_data = g_variant_get_data_as_bytes (commit_variant); + + /* The verify operation is merely to parse any existing signatures to + * check if the commit has already been signed with the given key ID. + * We want to avoid storing duplicate signatures in the metadata. We + * pass the homedir so that the signing key can be imported, allowing + * subkey signatures to be recognised. */ + g_autoptr(GError) local_error = NULL; + g_autoptr(GFile) verify_keydir = NULL; + if (homedir != NULL) + verify_keydir = g_file_new_for_path (homedir); + g_autoptr(OstreeGpgVerifyResult) result + =_ostree_repo_gpg_verify_with_metadata (self, commit_data, old_metadata, + NULL, verify_keydir, NULL, + cancellable, &local_error); + if (!result) + { + /* "Not found" just means the commit is not yet signed. That's okay. */ + if (g_error_matches (local_error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE)) + { + g_clear_error (&local_error); + } + else + return g_propagate_error (error, g_steal_pointer (&local_error)), FALSE; + } + else if (ostree_gpg_verify_result_lookup (result, key_id, NULL)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "Commit is already signed with GPG key %s", key_id); + return FALSE; + } + + if (!sign_data (self, commit_data, key_id, homedir, + &signature, cancellable, error)) + return FALSE; + + g_autoptr(GVariant) new_metadata = + _ostree_detached_metadata_append_gpg_sig (old_metadata, signature); + + if (!ostree_repo_write_commit_detached_metadata (self, + commit_checksum, + new_metadata, + cancellable, + error)) + return FALSE; + + return TRUE; +#else + /* FIXME: Return false until refactoring */ + return glnx_throw (error, "GPG feature is disabled in a build time"); +#endif /* OSTREE_DISABLE_GPGME */ +} + +/** + * ostree_repo_sign_delta: + * @self: Self + * @from_commit: From commit + * @to_commit: To commit + * @key_id: key id + * @homedir: homedir + * @cancellable: cancellable + * @error: error + * + * This function is deprecated, sign the summary file instead. + * Add a GPG signature to a static delta. + */ +gboolean +ostree_repo_sign_delta (OstreeRepo *self, + const gchar *from_commit, + const gchar *to_commit, + const gchar *key_id, + const gchar *homedir, + GCancellable *cancellable, + GError **error) +{ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "ostree_repo_sign_delta is deprecated"); + return FALSE; +} + +/** + * ostree_repo_add_gpg_signature_summary: + * @self: Self + * @key_id: (array zero-terminated=1) (element-type utf8): NULL-terminated array of GPG keys. + * @homedir: (allow-none): GPG home directory, or %NULL + * @cancellable: A #GCancellable + * @error: a #GError + * + * Add a GPG signature to a summary file. + */ +gboolean +ostree_repo_add_gpg_signature_summary (OstreeRepo *self, + const gchar **key_id, + const gchar *homedir, + GCancellable *cancellable, + GError **error) +{ +#ifndef OSTREE_DISABLE_GPGME + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (self->repo_dir_fd, "summary", TRUE, &fd, error)) + return FALSE; + g_autoptr(GBytes) summary_data = ot_fd_readall_or_mmap (fd, 0, error); + if (!summary_data) + return FALSE; + /* Note that fd is reused below */ + glnx_close_fd (&fd); + + g_autoptr(GVariant) metadata = NULL; + if (!ot_openat_ignore_enoent (self->repo_dir_fd, "summary.sig", &fd, error)) + return FALSE; + if (fd >= 0) + { + if (!ot_variant_read_fd (fd, 0, G_VARIANT_TYPE (OSTREE_SUMMARY_SIG_GVARIANT_STRING), + FALSE, &metadata, error)) + return FALSE; + } + + for (guint i = 0; key_id[i]; i++) + { + g_autoptr(GBytes) signature_data = NULL; + if (!sign_data (self, summary_data, key_id[i], homedir, + &signature_data, + cancellable, error)) + return FALSE; + + g_autoptr(GVariant) old_metadata = g_steal_pointer (&metadata); + metadata = _ostree_detached_metadata_append_gpg_sig (old_metadata, signature_data); + } + + g_autoptr(GVariant) normalized = g_variant_get_normal_form (metadata); + + if (!_ostree_repo_file_replace_contents (self, + self->repo_dir_fd, + "summary.sig", + g_variant_get_data (normalized), + g_variant_get_size (normalized), + cancellable, error)) + return FALSE; + + return TRUE; +#else + return glnx_throw (error, "GPG feature is disabled in a build time"); +#endif /* OSTREE_DISABLE_GPGME */ +} + +#ifndef OSTREE_DISABLE_GPGME +/* Special remote for _ostree_repo_gpg_verify_with_metadata() */ +static const char *OSTREE_ALL_REMOTES = "__OSTREE_ALL_REMOTES__"; + +/* Look for a keyring for @remote in the repo itself, or in + * /etc/ostree/remotes.d. + */ +static gboolean +find_keyring (OstreeRepo *self, + OstreeRemote *remote, + GBytes **ret_bytes, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int fd = -1; + if (!ot_openat_ignore_enoent (self->repo_dir_fd, remote->keyring, &fd, error)) + return FALSE; + + if (fd != -1) + { + GBytes *ret = glnx_fd_readall_bytes (fd, cancellable, error); + if (!ret) + return FALSE; + *ret_bytes = ret; + return TRUE; + } + + g_autoptr(GFile) remotes_d = get_remotes_d_dir (self, NULL); + if (remotes_d) + { + g_autoptr(GFile) child = g_file_get_child (remotes_d, remote->keyring); + + if (!ot_openat_ignore_enoent (AT_FDCWD, gs_file_get_path_cached (child), &fd, error)) + return FALSE; + + if (fd != -1) + { + GBytes *ret = glnx_fd_readall_bytes (fd, cancellable, error); + if (!ret) + return FALSE; + *ret_bytes = ret; + return TRUE; + } + } + + if (self->parent_repo) + return find_keyring (self->parent_repo, remote, ret_bytes, cancellable, error); + + *ret_bytes = NULL; + return TRUE; +} + +static OstreeGpgVerifyResult * +_ostree_repo_gpg_verify_data_internal (OstreeRepo *self, + const gchar *remote_name, + GBytes *data, + GBytes *signatures, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeGpgVerifier) verifier = NULL; + gboolean add_global_keyring_dir = TRUE; + + verifier = _ostree_gpg_verifier_new (); + + if (remote_name == OSTREE_ALL_REMOTES) + { + /* Add all available remote keyring files. */ + + if (!_ostree_gpg_verifier_add_keyring_dir_at (verifier, self->repo_dir_fd, ".", + cancellable, error)) + return NULL; + } + else if (remote_name != NULL) + { + /* Add the remote's keyring file if it exists. */ + + g_autoptr(OstreeRemote) remote = NULL; + + remote = _ostree_repo_get_remote_inherited (self, remote_name, error); + if (remote == NULL) + return NULL; + + g_autoptr(GBytes) keyring_data = NULL; + if (!find_keyring (self, remote, &keyring_data, cancellable, error)) + return NULL; + + if (keyring_data != NULL) + { + _ostree_gpg_verifier_add_keyring_data (verifier, keyring_data, remote->keyring); + add_global_keyring_dir = FALSE; + } + + g_auto(GStrv) gpgkeypath_list = NULL; + + if (!ot_keyfile_get_string_list_with_separator_choice (remote->options, + remote->group, + "gpgkeypath", + ";,", + &gpgkeypath_list, + error)) + return NULL; + + if (gpgkeypath_list) + { + for (char **iter = gpgkeypath_list; *iter != NULL; ++iter) + if (!_ostree_gpg_verifier_add_keyfile_path (verifier, *iter, + cancellable, error)) + return NULL; + } + } + + if (add_global_keyring_dir) + { + /* Use the deprecated global keyring directory. */ + if (!_ostree_gpg_verifier_add_global_keyring_dir (verifier, cancellable, error)) + return NULL; + } + + if (keyringdir) + { + if (!_ostree_gpg_verifier_add_keyring_dir (verifier, keyringdir, + cancellable, error)) + return NULL; + } + if (extra_keyring != NULL) + { + _ostree_gpg_verifier_add_keyring_file (verifier, extra_keyring); + } + + return _ostree_gpg_verifier_check_signature (verifier, + data, + signatures, + cancellable, + error); +} + +OstreeGpgVerifyResult * +_ostree_repo_gpg_verify_with_metadata (OstreeRepo *self, + GBytes *signed_data, + GVariant *metadata, + const char *remote_name, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) signaturedata = NULL; + GByteArray *buffer; + GVariantIter iter; + GVariant *child; + g_autoptr (GBytes) signatures = NULL; + + if (metadata) + signaturedata = g_variant_lookup_value (metadata, + _OSTREE_METADATA_GPGSIGS_NAME, + _OSTREE_METADATA_GPGSIGS_TYPE); + if (!signaturedata) + { + g_set_error_literal (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, + "GPG verification enabled, but no signatures found (use gpg-verify=false in remote config to disable)"); + return NULL; + } + + /* OpenPGP data is organized into binary records called packets. RFC 4880 + * defines a packet as a chunk of data that has a tag specifying its meaning, + * and consists of a packet header followed by a packet body. Each packet + * encodes its own length, and so packets can be concatenated to construct + * OpenPGP messages, keyrings, or in this case, detached signatures. + * + * Each binary blob in the GVariant list is a complete signature packet, so + * we can concatenate them together to verify all the signatures at once. */ + buffer = g_byte_array_new (); + g_variant_iter_init (&iter, signaturedata); + while ((child = g_variant_iter_next_value (&iter)) != NULL) + { + g_byte_array_append (buffer, + g_variant_get_data (child), + g_variant_get_size (child)); + g_variant_unref (child); + } + signatures = g_byte_array_free_to_bytes (buffer); + + return _ostree_repo_gpg_verify_data_internal (self, + remote_name, + signed_data, + signatures, + keyringdir, + extra_keyring, + cancellable, + error); +} + +/* Needed an internal version for the remote_name parameter. */ +OstreeGpgVerifyResult * +_ostree_repo_verify_commit_internal (OstreeRepo *self, + const char *commit_checksum, + const char *remote_name, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) commit_variant = NULL; + /* Load the commit */ + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, + commit_checksum, &commit_variant, + error)) + return glnx_prefix_error_null (error, "Failed to read commit"); + + /* Load the metadata */ + g_autoptr(GVariant) metadata = NULL; + if (!ostree_repo_read_commit_detached_metadata (self, + commit_checksum, + &metadata, + cancellable, + error)) + return glnx_prefix_error_null (error, "Failed to read detached metadata"); + + g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit_variant); + + /* XXX This is a hackish way to indicate to use ALL remote-specific + * keyrings in the signature verification. We want this when + * verifying a signed commit that's already been pulled. */ + if (remote_name == NULL) + remote_name = OSTREE_ALL_REMOTES; + + return _ostree_repo_gpg_verify_with_metadata (self, signed_data, + metadata, remote_name, + keyringdir, extra_keyring, + cancellable, error); +} +#endif /* OSTREE_DISABLE_GPGME */ + +/** + * ostree_repo_verify_commit: + * @self: Repository + * @commit_checksum: ASCII SHA256 checksum + * @keyringdir: (allow-none): Path to directory GPG keyrings; overrides built-in default if given + * @extra_keyring: (allow-none): Path to additional keyring file (not a directory) + * @cancellable: Cancellable + * @error: Error + * + * Check for a valid GPG signature on commit named by the ASCII + * checksum @commit_checksum. + * + * Returns: %TRUE if there was a GPG signature from a trusted keyring, otherwise %FALSE + */ +gboolean +ostree_repo_verify_commit (OstreeRepo *self, + const gchar *commit_checksum, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error) +{ +#ifndef OSTREE_DISABLE_GPGME + g_autoptr(OstreeGpgVerifyResult) result = NULL; + + result = ostree_repo_verify_commit_ext (self, commit_checksum, + keyringdir, extra_keyring, + cancellable, error); + + if (!ostree_gpg_verify_result_require_valid_signature (result, error)) + return glnx_prefix_error (error, "Commit %s", commit_checksum); + return TRUE; +#else + /* FIXME: Return false until refactoring */ + return glnx_throw (error, "GPG feature is disabled in a build time"); +#endif /* OSTREE_DISABLE_GPGME */ +} + +/** + * ostree_repo_verify_commit_ext: + * @self: Repository + * @commit_checksum: ASCII SHA256 checksum + * @keyringdir: (allow-none): Path to directory GPG keyrings; overrides built-in default if given + * @extra_keyring: (allow-none): Path to additional keyring file (not a directory) + * @cancellable: Cancellable + * @error: Error + * + * Read GPG signature(s) on the commit named by the ASCII checksum + * @commit_checksum and return detailed results. + * + * Returns: (transfer full): an #OstreeGpgVerifyResult, or %NULL on error + */ +OstreeGpgVerifyResult * +ostree_repo_verify_commit_ext (OstreeRepo *self, + const gchar *commit_checksum, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error) +{ +#ifndef OSTREE_DISABLE_GPGME + return _ostree_repo_verify_commit_internal (self, + commit_checksum, + NULL, + keyringdir, + extra_keyring, + cancellable, + error); +#else + glnx_throw (error, "GPG feature is disabled in a build time"); + return NULL; +#endif /* OSTREE_DISABLE_GPGME */ +} + +/** + * ostree_repo_verify_commit_for_remote: + * @self: Repository + * @commit_checksum: ASCII SHA256 checksum + * @remote_name: OSTree remote to use for configuration + * @cancellable: Cancellable + * @error: Error + * + * Read GPG signature(s) on the commit named by the ASCII checksum + * @commit_checksum and return detailed results, based on the keyring + * configured for @remote. + * + * Returns: (transfer full): an #OstreeGpgVerifyResult, or %NULL on error + * + * Since: 2016.14 + */ +OstreeGpgVerifyResult * +ostree_repo_verify_commit_for_remote (OstreeRepo *self, + const gchar *commit_checksum, + const gchar *remote_name, + GCancellable *cancellable, + GError **error) +{ +#ifndef OSTREE_DISABLE_GPGME + return _ostree_repo_verify_commit_internal (self, + commit_checksum, + remote_name, + NULL, + NULL, + cancellable, + error); +#else + glnx_throw (error, "GPG feature is disabled in a build time"); + return NULL; +#endif /* OSTREE_DISABLE_GPGME */ +} + +/** + * ostree_repo_gpg_verify_data: + * @self: Repository + * @remote_name: (nullable): Name of remote + * @data: Data as a #GBytes + * @signatures: Signatures as a #GBytes + * @keyringdir: (nullable): Path to directory GPG keyrings; overrides built-in default if given + * @extra_keyring: (nullable): Path to additional keyring file (not a directory) + * @cancellable: Cancellable + * @error: Error + * + * Verify @signatures for @data using GPG keys in the keyring for + * @remote_name, and return an #OstreeGpgVerifyResult. + * + * The @remote_name parameter can be %NULL. In that case it will do + * the verifications using GPG keys in the keyrings of all remotes. + * + * Returns: (transfer full): an #OstreeGpgVerifyResult, or %NULL on error + * + * Since: 2016.6 + */ +OstreeGpgVerifyResult * +ostree_repo_gpg_verify_data (OstreeRepo *self, + const gchar *remote_name, + GBytes *data, + GBytes *signatures, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (signatures != NULL, NULL); + +#ifndef OSTREE_DISABLE_GPGME + return _ostree_repo_gpg_verify_data_internal (self, + (remote_name != NULL) ? remote_name : OSTREE_ALL_REMOTES, + data, + signatures, + keyringdir, + extra_keyring, + cancellable, + error); +#else + glnx_throw (error, "GPG feature is disabled in a build time"); + return NULL; +#endif /* OSTREE_DISABLE_GPGME */ +} + +/** + * ostree_repo_verify_summary: + * @self: Repo + * @remote_name: Name of remote + * @summary: Summary data as a #GBytes + * @signatures: Summary signatures as a #GBytes + * @cancellable: Cancellable + * @error: Error + * + * Verify @signatures for @summary data using GPG keys in the keyring for + * @remote_name, and return an #OstreeGpgVerifyResult. + * + * Returns: (transfer full): an #OstreeGpgVerifyResult, or %NULL on error + */ +OstreeGpgVerifyResult * +ostree_repo_verify_summary (OstreeRepo *self, + const char *remote_name, + GBytes *summary, + GBytes *signatures, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) signatures_variant = NULL; + + g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); + g_return_val_if_fail (remote_name != NULL, NULL); + g_return_val_if_fail (summary != NULL, NULL); + g_return_val_if_fail (signatures != NULL, NULL); + + signatures_variant = g_variant_new_from_bytes (OSTREE_SUMMARY_SIG_GVARIANT_FORMAT, + signatures, FALSE); + +#ifndef OSTREE_DISABLE_GPGME + return _ostree_repo_gpg_verify_with_metadata (self, + summary, + signatures_variant, + remote_name, + NULL, NULL, + cancellable, + error); +#else + glnx_throw (error, "GPG feature is disabled in a build time"); + return NULL; +#endif /* OSTREE_DISABLE_GPGME */ +} + +/* Add an entry for a @ref ↦ @checksum mapping to an `a(s(t@ay@a{sv}))` + * @refs_builder to go into a `summary` file. This includes building the + * standard additional metadata keys for the ref. */ +static gboolean +summary_add_ref_entry (OstreeRepo *self, + const char *ref, + const char *checksum, + GVariantBuilder *refs_builder, + GError **error) +{ + g_auto(GVariantDict) commit_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER; + + g_assert (ref); g_assert (checksum); + + g_autofree char *remotename = NULL; + if (!ostree_parse_refspec (ref, &remotename, NULL, NULL)) + g_assert_not_reached (); + + /* Don't put remote refs in the summary */ + if (remotename != NULL) + return TRUE; + + g_autoptr(GVariant) commit_obj = NULL; + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, checksum, &commit_obj, error)) + return FALSE; + + g_variant_dict_init (&commit_metadata_builder, NULL); + + /* Forward the commit’s timestamp if it’s valid. */ + guint64 commit_timestamp = ostree_commit_get_timestamp (commit_obj); + g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (commit_timestamp); + + if (dt != NULL) + g_variant_dict_insert_value (&commit_metadata_builder, OSTREE_COMMIT_TIMESTAMP, + g_variant_new_uint64 (GUINT64_TO_BE (commit_timestamp))); + + g_variant_builder_add_value (refs_builder, + g_variant_new ("(s(t@ay@a{sv}))", ref, + (guint64) g_variant_get_size (commit_obj), + ostree_checksum_to_bytes_v (checksum), + g_variant_dict_end (&commit_metadata_builder))); + + return TRUE; +} + +/** + * ostree_repo_regenerate_summary: + * @self: Repo + * @additional_metadata: (allow-none): A GVariant of type a{sv}, or %NULL + * @cancellable: Cancellable + * @error: Error + * + * An OSTree repository can contain a high level "summary" file that + * describes the available branches and other metadata. + * + * If the timetable for making commits and updating the summary file is fairly + * regular, setting the `ostree.summary.expires` key in @additional_metadata + * will aid clients in working out when to check for updates. + * + * It is regenerated automatically after any ref is + * added, removed, or updated if `core/auto-update-summary` is set. + * + * If the `core/collection-id` key is set in the configuration, it will be + * included as %OSTREE_SUMMARY_COLLECTION_ID in the summary file. Refs that + * have associated collection IDs will be included in the generated summary + * file, listed under the %OSTREE_SUMMARY_COLLECTION_MAP key. Collection IDs + * and refs in %OSTREE_SUMMARY_COLLECTION_MAP are guaranteed to be in + * lexicographic order. + * + * Locking: exclusive + */ +gboolean +ostree_repo_regenerate_summary (OstreeRepo *self, + GVariant *additional_metadata, + GCancellable *cancellable, + GError **error) +{ + /* Take an exclusive lock. This makes sure the commits and deltas don't get + * deleted while generating the summary. It also means we can be sure refs + * won't be created/updated/deleted during the operation, without having to + * add exclusive locks to those operations which would prevent concurrent + * commits from working. + */ + g_autoptr(OstreeRepoAutoLock) lock = NULL; + lock = _ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, + cancellable, error); + if (!lock) + return FALSE; + + g_auto(GVariantDict) additional_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER; + g_variant_dict_init (&additional_metadata_builder, additional_metadata); + g_autoptr(GVariantBuilder) refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(s(taya{sv}))")); + + const gchar *main_collection_id = ostree_repo_get_collection_id (self); + + { + if (main_collection_id == NULL) + { + g_autoptr(GHashTable) refs = NULL; + if (!ostree_repo_list_refs (self, NULL, &refs, cancellable, error)) + return FALSE; + + g_autoptr(GList) ordered_keys = g_hash_table_get_keys (refs); + ordered_keys = g_list_sort (ordered_keys, (GCompareFunc)strcmp); + + for (GList *iter = ordered_keys; iter; iter = iter->next) + { + const char *ref = iter->data; + const char *commit = g_hash_table_lookup (refs, ref); + + if (!summary_add_ref_entry (self, ref, commit, refs_builder, error)) + return FALSE; + } + } + } + + { + g_autoptr(GPtrArray) delta_names = NULL; + g_auto(GVariantDict) deltas_builder = OT_VARIANT_BUILDER_INITIALIZER; + + if (!ostree_repo_list_static_delta_names (self, &delta_names, cancellable, error)) + return FALSE; + + g_variant_dict_init (&deltas_builder, NULL); + for (guint i = 0; i < delta_names->len; i++) + { + g_autofree char *from = NULL; + g_autofree char *to = NULL; + if (!_ostree_parse_delta_name (delta_names->pdata[i], &from, &to, error)) + return FALSE; + + g_autofree char *superblock = _ostree_get_relative_static_delta_superblock_path ((from && from[0]) ? from : NULL, to); + glnx_autofd int superblock_file_fd = -1; + + if (!glnx_openat_rdonly (self->repo_dir_fd, superblock, TRUE, &superblock_file_fd, error)) + return FALSE; + + g_autoptr(GBytes) superblock_content = ot_fd_readall_or_mmap (superblock_file_fd, 0, error); + if (!superblock_content) + return FALSE; + g_auto(OtChecksum) hasher = { 0, }; + ot_checksum_init (&hasher); + ot_checksum_update_bytes (&hasher, superblock_content); + guint8 digest[OSTREE_SHA256_DIGEST_LEN]; + ot_checksum_get_digest (&hasher, digest, sizeof (digest)); + + g_variant_dict_insert_value (&deltas_builder, delta_names->pdata[i], ot_gvariant_new_bytearray (digest, sizeof (digest))); + } + + if (delta_names->len > 0) + g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_STATIC_DELTAS, g_variant_dict_end (&deltas_builder)); + } + + { + g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_LAST_MODIFIED, + g_variant_new_uint64 (GUINT64_TO_BE (g_get_real_time () / G_USEC_PER_SEC))); + } + + /* Add refs which have a collection specified, which could be in refs/mirrors, + * refs/heads, and/or refs/remotes. */ + { + g_autoptr(GHashTable) collection_refs = NULL; + if (!ostree_repo_list_collection_refs (self, NULL, &collection_refs, + OSTREE_REPO_LIST_REFS_EXT_NONE, cancellable, error)) + return FALSE; + + gsize collection_map_size = 0; + GHashTableIter iter; + g_autoptr(GHashTable) collection_map = NULL; /* (element-type utf8 GHashTable) */ + g_hash_table_iter_init (&iter, collection_refs); + collection_map = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, + (GDestroyNotify) g_hash_table_unref); + + const OstreeCollectionRef *ref; + const char *checksum; + while (g_hash_table_iter_next (&iter, (gpointer *) &ref, (gpointer *) &checksum)) + { + GHashTable *ref_map = g_hash_table_lookup (collection_map, ref->collection_id); + + if (ref_map == NULL) + { + ref_map = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + g_hash_table_insert (collection_map, ref->collection_id, ref_map); + } + + g_hash_table_insert (ref_map, ref->ref_name, (gpointer) checksum); + } + + g_autoptr(GVariantBuilder) collection_refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sa(s(taya{sv}))}")); + + g_autoptr(GList) ordered_collection_ids = g_hash_table_get_keys (collection_map); + ordered_collection_ids = g_list_sort (ordered_collection_ids, (GCompareFunc) strcmp); + + for (GList *collection_iter = ordered_collection_ids; collection_iter; collection_iter = collection_iter->next) + { + const char *collection_id = collection_iter->data; + GHashTable *ref_map = g_hash_table_lookup (collection_map, collection_id); + + /* We put the local repo's collection ID in the main refs map, rather + * than the collection map, for backwards compatibility. */ + gboolean is_main_collection_id = (main_collection_id != NULL && g_str_equal (collection_id, main_collection_id)); + + if (!is_main_collection_id) + { + g_variant_builder_open (collection_refs_builder, G_VARIANT_TYPE ("{sa(s(taya{sv}))}")); + g_variant_builder_add (collection_refs_builder, "s", collection_id); + g_variant_builder_open (collection_refs_builder, G_VARIANT_TYPE ("a(s(taya{sv}))")); + } + + g_autoptr(GList) ordered_refs = g_hash_table_get_keys (ref_map); + ordered_refs = g_list_sort (ordered_refs, (GCompareFunc) strcmp); + + for (GList *ref_iter = ordered_refs; ref_iter != NULL; ref_iter = ref_iter->next) + { + const char *ref = ref_iter->data; + const char *commit = g_hash_table_lookup (ref_map, ref); + GVariantBuilder *builder = is_main_collection_id ? refs_builder : collection_refs_builder; + + if (!summary_add_ref_entry (self, ref, commit, builder, error)) + return FALSE; + + if (!is_main_collection_id) + collection_map_size++; + } + + if (!is_main_collection_id) + { + g_variant_builder_close (collection_refs_builder); /* array */ + g_variant_builder_close (collection_refs_builder); /* dict entry */ + } + } + + if (main_collection_id != NULL) + g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_COLLECTION_ID, + g_variant_new_string (main_collection_id)); + if (collection_map_size > 0) + g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_COLLECTION_MAP, + g_variant_builder_end (collection_refs_builder)); + } + + g_autoptr(GVariant) summary = NULL; + { + g_autoptr(GVariantBuilder) summary_builder = + g_variant_builder_new (OSTREE_SUMMARY_GVARIANT_FORMAT); + + g_variant_builder_add_value (summary_builder, g_variant_builder_end (refs_builder)); + g_variant_builder_add_value (summary_builder, g_variant_dict_end (&additional_metadata_builder)); + summary = g_variant_builder_end (summary_builder); + g_variant_ref_sink (summary); + } + + if (!_ostree_repo_file_replace_contents (self, + self->repo_dir_fd, + "summary", + g_variant_get_data (summary), + g_variant_get_size (summary), + cancellable, + error)) + return FALSE; + + if (!ot_ensure_unlinked_at (self->repo_dir_fd, "summary.sig", error)) + return FALSE; + + return TRUE; +} + +/* Regenerate the summary if `core/auto-update-summary` is set. We default to FALSE for + * this setting because OSTree supports multiple processes committing to the same repo (but + * different refs) concurrently, and in fact gnome-continuous actually does this. In that + * context it's best to update the summary explicitly once at the end of multiple + * transactions instead of automatically here. `auto-update-summary` only updates + * atomically within a transaction. */ +gboolean +_ostree_repo_maybe_regenerate_summary (OstreeRepo *self, + GCancellable *cancellable, + GError **error) +{ + gboolean auto_update_summary; + if (!ot_keyfile_get_boolean_with_default (self->config, "core", + "auto-update-summary", FALSE, + &auto_update_summary, error)) + return FALSE; + + /* Deprecated alias for `auto-update-summary`. */ + gboolean commit_update_summary; + if (!ot_keyfile_get_boolean_with_default (self->config, "core", + "commit-update-summary", FALSE, + &commit_update_summary, error)) + return FALSE; + + if ((auto_update_summary || commit_update_summary) && + !ostree_repo_regenerate_summary (self, NULL, cancellable, error)) + return FALSE; + + return TRUE; +} + +gboolean +_ostree_repo_has_staging_prefix (const char *filename) +{ + return g_str_has_prefix (filename, OSTREE_REPO_TMPDIR_STAGING); +} + +gboolean +_ostree_repo_try_lock_tmpdir (int tmpdir_dfd, + const char *tmpdir_name, + GLnxLockFile *file_lock_out, + gboolean *out_did_lock, + GError **error) +{ + g_autofree char *lock_name = g_strconcat (tmpdir_name, "-lock", NULL); + gboolean did_lock = FALSE; + g_autoptr(GError) local_error = NULL; + + /* We put the lock outside the dir, so we can hold the lock + * until the directory is fully removed */ + if (!glnx_make_lock_file (tmpdir_dfd, lock_name, LOCK_EX | LOCK_NB, + file_lock_out, &local_error)) + { + /* we need to handle EACCES too in the case of POSIX locks; see F_SETLK in fcntl(2) */ + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) + || g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) + { + did_lock = FALSE; + } + else + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + else + { + /* It's possible that we got a lock after seeing the directory, but + * another process deleted the tmpdir, so verify it still exists. + */ + struct stat stbuf; + if (!glnx_fstatat_allow_noent (tmpdir_dfd, tmpdir_name, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == 0 && S_ISDIR (stbuf.st_mode)) + did_lock = TRUE; + else + glnx_release_lock_file (file_lock_out); + } + + *out_did_lock = did_lock; + return TRUE; +} + +/* This allocates and locks a subdir of the repo tmp dir, using an existing + * one with the same prefix if it is not in use already. */ +gboolean +_ostree_repo_allocate_tmpdir (int tmpdir_dfd, + const char *tmpdir_prefix, + GLnxTmpDir *tmpdir_out, + GLnxLockFile *file_lock_out, + gboolean *reusing_dir_out, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (_ostree_repo_has_staging_prefix (tmpdir_prefix), FALSE); + + /* Look for existing tmpdir (with same prefix) to reuse */ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_at (tmpdir_dfd, ".", FALSE, &dfd_iter, error)) + return FALSE; + + gboolean reusing_dir = FALSE; + gboolean did_lock = FALSE; + g_auto(GLnxTmpDir) ret_tmpdir = { 0, }; + while (!ret_tmpdir.initialized) + { + struct dirent *dent; + g_autoptr(GError) local_error = NULL; + + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) + return FALSE; + + if (dent == NULL) + break; + + if (!g_str_has_prefix (dent->d_name, tmpdir_prefix)) + continue; + + /* Quickly skip non-dirs, if unknown we ignore ENOTDIR when opening instead */ + if (dent->d_type != DT_UNKNOWN && + dent->d_type != DT_DIR) + continue; + + glnx_autofd int target_dfd = -1; + if (!glnx_opendirat (dfd_iter.fd, dent->d_name, FALSE, + &target_dfd, &local_error)) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY) || + g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + continue; + else + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + + /* We put the lock outside the dir, so we can hold the lock + * until the directory is fully removed */ + if (!_ostree_repo_try_lock_tmpdir (tmpdir_dfd, dent->d_name, + file_lock_out, &did_lock, + error)) + return FALSE; + if (!did_lock) + continue; + + /* Touch the reused directory so that we don't accidentally + * remove it due to being old when cleaning up the tmpdir. + */ + (void)futimens (target_dfd, NULL); + + /* We found an existing tmpdir which we managed to lock */ + g_debug ("Reusing tmpdir %s", dent->d_name); + reusing_dir = TRUE; + ret_tmpdir.src_dfd = tmpdir_dfd; + ret_tmpdir.fd = glnx_steal_fd (&target_dfd); + ret_tmpdir.path = g_strdup (dent->d_name); + ret_tmpdir.initialized = TRUE; + } + + const char *tmpdir_name_template = glnx_strjoina (tmpdir_prefix, "XXXXXX"); + while (!ret_tmpdir.initialized) + { + g_auto(GLnxTmpDir) new_tmpdir = { 0, }; + /* No existing tmpdir found, create a new */ + if (!glnx_mkdtempat (tmpdir_dfd, tmpdir_name_template, DEFAULT_DIRECTORY_MODE, + &new_tmpdir, error)) + return FALSE; + + /* Note, at this point we can race with another process that picks up this + * new directory. If that happens we need to retry, making a new directory. */ + if (!_ostree_repo_try_lock_tmpdir (new_tmpdir.src_dfd, new_tmpdir.path, + file_lock_out, &did_lock, + error)) + return FALSE; + if (!did_lock) + { + /* We raced and someone else already locked the newly created + * directory. Free the resources here and then mark it as + * uninitialized so glnx_tmpdir_cleanup doesn't delete the directory + * when new_tmpdir goes out of scope. + */ + glnx_tmpdir_unset (&new_tmpdir); + new_tmpdir.initialized = FALSE; + continue; + } + + g_debug ("Using new tmpdir %s", new_tmpdir.path); + ret_tmpdir = new_tmpdir; /* Transfer ownership */ + new_tmpdir.initialized = FALSE; + } + + *tmpdir_out = ret_tmpdir; /* Transfer ownership */ + ret_tmpdir.initialized = FALSE; + *reusing_dir_out = reusing_dir; + return TRUE; +} + +/* See ostree-repo-private.h for more information about this */ +void +_ostree_repo_memory_cache_ref_init (OstreeRepoMemoryCacheRef *state, + OstreeRepo *repo) +{ + state->repo = g_object_ref (repo); + GMutex *lock = &repo->cache_lock; + g_mutex_lock (lock); + repo->dirmeta_cache_refcount++; + if (repo->dirmeta_cache == NULL) + repo->dirmeta_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); + g_mutex_unlock (lock); + +} + +/* See ostree-repo-private.h for more information about this */ +void +_ostree_repo_memory_cache_ref_destroy (OstreeRepoMemoryCacheRef *state) +{ + OstreeRepo *repo = state->repo; + GMutex *lock = &repo->cache_lock; + g_mutex_lock (lock); + repo->dirmeta_cache_refcount--; + if (repo->dirmeta_cache_refcount == 0) + g_clear_pointer (&repo->dirmeta_cache, (GDestroyNotify) g_hash_table_unref); + g_mutex_unlock (lock); + g_object_unref (repo); +} + +/** + * ostree_repo_get_collection_id: + * @self: an #OstreeRepo + * + * Get the collection ID of this repository. See [collection IDs][collection-ids]. + * + * Returns: (nullable): collection ID for the repository + * Since: 2018.6 + */ +const gchar * +ostree_repo_get_collection_id (OstreeRepo *self) +{ + g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); + + return self->collection_id; +} + +/** + * ostree_repo_set_collection_id: + * @self: an #OstreeRepo + * @collection_id: (nullable): new collection ID, or %NULL to unset it + * @error: return location for a #GError, or %NULL + * + * Set or clear the collection ID of this repository. See [collection IDs][collection-ids]. + * The update will be made in memory, but must be written out to the repository + * configuration on disk using ostree_repo_write_config(). + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: 2018.6 + */ +gboolean +ostree_repo_set_collection_id (OstreeRepo *self, + const gchar *collection_id, + GError **error) +{ + if (collection_id != NULL && !ostree_validate_collection_id (collection_id, error)) + return FALSE; + + g_autofree gchar *new_collection_id = g_strdup (collection_id); + g_free (self->collection_id); + self->collection_id = g_steal_pointer (&new_collection_id); + + if (self->config != NULL) + { + if (collection_id != NULL) + g_key_file_set_string (self->config, "core", "collection-id", collection_id); + else + return g_key_file_remove_key (self->config, "core", "collection-id", error); + } + + return TRUE; +} + +/** + * ostree_repo_get_default_repo_finders: + * @self: an #OstreeRepo + * + * Get the set of default repo finders configured. See the documentation for + * the "core.default-repo-finders" config key. + * + * Returns: (array zero-terminated=1) (element-type utf8): + * %NULL-terminated array of strings. + * Since: 2018.9 + */ +const gchar * const * +ostree_repo_get_default_repo_finders (OstreeRepo *self) +{ + g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); + + return (const gchar * const *)self->repo_finders; +} + +/** + * ostree_repo_get_bootloader: + * @self: an #OstreeRepo + * + * Get the bootloader configured. See the documentation for the + * "sysroot.bootloader" config key. + * + * Returns: bootloader configuration for the sysroot + * Since: 2019.2 + */ +const gchar * +ostree_repo_get_bootloader (OstreeRepo *self) +{ + g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); + + return self->bootloader; +} + + +/** + * _ostree_repo_verify_bindings: + * @collection_id: (nullable): Locally specified collection ID for the remote + * the @commit was retrieved from, or %NULL if none is configured + * @ref_name: (nullable): Ref name the commit was retrieved using, or %NULL if + * the commit was retrieved by checksum + * @commit: Commit data to check + * @error: Return location for a #GError, or %NULL + * + * Verify the ref and collection bindings. + * + * The ref binding is verified only if it exists. But if we have the + * collection ID specified in the remote configuration (@collection_id is + * non-%NULL) then the ref binding must exist, otherwise the verification will + * fail. Parts of the verification can be skipped by passing %NULL to the + * @ref_name parameter (in case we requested a checksum directly, without + * looking it up from a ref). + * + * The collection binding is verified only when we have collection ID + * specified in the remote configuration. If it is specified, then the + * binding must exist and must be equal to the remote repository + * collection ID. + * + * Returns: %TRUE if bindings are correct, %FALSE otherwise + * Since: 2017.14 + */ +gboolean +_ostree_repo_verify_bindings (const char *collection_id, + const char *ref_name, + GVariant *commit, + GError **error) +{ + g_autoptr(GVariant) metadata = g_variant_get_child_value (commit, 0); + g_autofree const char **refs = NULL; + if (!g_variant_lookup (metadata, + OSTREE_COMMIT_META_KEY_REF_BINDING, + "^a&s", + &refs)) + { + /* Early return here - if the remote collection ID is NULL, then + * we certainly will not verify the collection binding in the + * commit. + */ + if (collection_id == NULL) + return TRUE; + + return glnx_throw (error, + "Expected commit metadata to have ref " + "binding information, found none"); + } + + if (ref_name != NULL) + { + if (!g_strv_contains ((const char *const *) refs, ref_name)) + { + g_autoptr(GString) refs_dump = g_string_new (NULL); + const char *refs_str; + + if (refs != NULL && (*refs) != NULL) + { + for (const char **iter = refs; *iter != NULL; ++iter) + { + const char *ref = *iter; + + if (refs_dump->len > 0) + g_string_append (refs_dump, ", "); + g_string_append_printf (refs_dump, "‘%s’", ref); + } + + refs_str = refs_dump->str; + } + else + { + refs_str = "no refs"; + } + + return glnx_throw (error, "Commit has no requested ref ‘%s’ " + "in ref binding metadata (%s)", + ref_name, refs_str); + } + } + + if (collection_id != NULL) + { + const char *collection_id_binding; + if (!g_variant_lookup (metadata, + OSTREE_COMMIT_META_KEY_COLLECTION_BINDING, + "&s", + &collection_id_binding)) + return glnx_throw (error, + "Expected commit metadata to have collection ID " + "binding information, found none"); + if (!g_str_equal (collection_id_binding, collection_id)) + return glnx_throw (error, + "Commit has collection ID ‘%s’ in collection binding " + "metadata, while the remote it came from has " + "collection ID ‘%s’", + collection_id_binding, collection_id); + } + + return TRUE; +} diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h new file mode 100644 index 0000000..e28af29 --- /dev/null +++ b/src/libostree/ostree-repo.h @@ -0,0 +1,1471 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include + +#include "ostree-core.h" +#include "ostree-types.h" +#include "ostree-async-progress.h" +#include "ostree-ref.h" +#include "ostree-repo-finder.h" +#include "ostree-sepolicy.h" +#include "ostree-gpg-verify-result.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_REPO ostree_repo_get_type() +#define OSTREE_REPO(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_REPO, OstreeRepo)) +#define OSTREE_IS_REPO(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_REPO)) + +_OSTREE_PUBLIC +gboolean ostree_repo_mode_from_string (const char *mode, + OstreeRepoMode *out_mode, + GError **error); + +_OSTREE_PUBLIC +GType ostree_repo_get_type (void); + +_OSTREE_PUBLIC +OstreeRepo* ostree_repo_new (GFile *path); + +_OSTREE_PUBLIC +OstreeRepo* ostree_repo_new_for_sysroot_path (GFile *repo_path, + GFile *sysroot_path); + +_OSTREE_PUBLIC +OstreeRepo* ostree_repo_new_default (void); + +_OSTREE_PUBLIC +gboolean ostree_repo_open (OstreeRepo *self, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeRepo* +ostree_repo_open_at (int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_set_disable_fsync (OstreeRepo *self, + gboolean disable_fsync); + +_OSTREE_PUBLIC +gboolean ostree_repo_set_cache_dir (OstreeRepo *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_get_disable_fsync (OstreeRepo *self); + +_OSTREE_PUBLIC +gboolean ostree_repo_is_system (OstreeRepo *repo); + +_OSTREE_PUBLIC +gboolean ostree_repo_is_writable (OstreeRepo *self, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_create (OstreeRepo *self, + OstreeRepoMode mode, + GCancellable *cancellable, + GError **error); +_OSTREE_PUBLIC +OstreeRepo * ostree_repo_create_at (int dfd, + const char *path, + OstreeRepoMode mode, + GVariant *options, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +const gchar * ostree_repo_get_collection_id (OstreeRepo *self); +_OSTREE_PUBLIC +gboolean ostree_repo_set_collection_id (OstreeRepo *self, + const gchar *collection_id, + GError **error); + +_OSTREE_PUBLIC +const gchar * const * ostree_repo_get_default_repo_finders (OstreeRepo *self); + +_OSTREE_PUBLIC +const gchar * ostree_repo_get_bootloader (OstreeRepo *self); + +_OSTREE_PUBLIC +GFile * ostree_repo_get_path (OstreeRepo *self); + +_OSTREE_PUBLIC +int ostree_repo_get_dfd (OstreeRepo *self); + +_OSTREE_PUBLIC +guint ostree_repo_hash (OstreeRepo *self); +_OSTREE_PUBLIC +gboolean ostree_repo_equal (OstreeRepo *a, + OstreeRepo *b); + +_OSTREE_PUBLIC +OstreeRepoMode ostree_repo_get_mode (OstreeRepo *self); + +_OSTREE_PUBLIC +gboolean ostree_repo_get_min_free_space_bytes (OstreeRepo *self, + guint64 *out_reserved_bytes, + GError **error); +_OSTREE_PUBLIC +GKeyFile * ostree_repo_get_config (OstreeRepo *self); + +_OSTREE_PUBLIC +GKeyFile * ostree_repo_copy_config (OstreeRepo *self); + +_OSTREE_PUBLIC +gboolean ostree_repo_reload_config (OstreeRepo *self, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_add (OstreeRepo *self, + const char *name, + const char *url, + GVariant *options, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_delete (OstreeRepo *self, + const char *name, + GCancellable *cancellable, + GError **error); + +/** + * OstreeRepoRemoteChange: + * The remote change operation. + * @OSTREE_REPO_REMOTE_CHANGE_ADD: Add a remote + * @OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS: Like above, but do nothing if the remote exists + * @OSTREE_REPO_REMOTE_CHANGE_DELETE: Delete a remote + * @OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS: Delete a remote, do nothing if the remote does not exist + * @OSTREE_REPO_REMOTE_CHANGE_REPLACE: Add or replace a remote (Since: 2019.2) + */ +typedef enum { + OSTREE_REPO_REMOTE_CHANGE_ADD, + OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS, + OSTREE_REPO_REMOTE_CHANGE_DELETE, + OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS, + OSTREE_REPO_REMOTE_CHANGE_REPLACE, +} OstreeRepoRemoteChange; + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_change (OstreeRepo *self, + GFile *sysroot, + OstreeRepoRemoteChange changeop, + const char *name, + const char *url, + GVariant *options, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +char ** ostree_repo_remote_list (OstreeRepo *self, + guint *out_n_remotes); + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_get_url (OstreeRepo *self, + const char *name, + char **out_url, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_get_remote_option (OstreeRepo *self, + const char *remote_name, + const char *option_name, + const char *default_value, + char **out_value, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_get_remote_list_option (OstreeRepo *self, + const char *remote_name, + const char *option_name, + char ***out_value, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_get_remote_boolean_option (OstreeRepo *self, + const char *remote_name, + const char *option_name, + gboolean default_value, + gboolean *out_value, + GError **error); + + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_fetch_summary (OstreeRepo *self, + const char *name, + GBytes **out_summary, + GBytes **out_signatures, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self, + const char *name, + GVariant *options, + GBytes **out_summary, + GBytes **out_signatures, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeRepo * ostree_repo_get_parent (OstreeRepo *self); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_config (OstreeRepo *self, + GKeyFile *new_config, + GError **error); + +/** + * OstreeRepoCommitState: + * @OSTREE_REPO_COMMIT_STATE_NORMAL: Commit is complete. This is the default. + * (Since: 2017.14.) + * @OSTREE_REPO_COMMIT_STATE_PARTIAL: One or more objects are missing from the + * local copy of the commit, but metadata is present. (Since: 2015.7.) + * @OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL: One or more objects are missing from the + * local copy of the commit, due to an fsck --delete. (Since: 2019.4.) + * + * Flags representing the state of a commit in the local repository, as returned + * by ostree_repo_load_commit(). + * + * Since: 2015.7 + */ +typedef enum { + OSTREE_REPO_COMMIT_STATE_NORMAL = 0, + OSTREE_REPO_COMMIT_STATE_PARTIAL = (1 << 0), + OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL = (1 << 1), +} OstreeRepoCommitState; + +/** + * OstreeRepoTransactionStats: + * @metadata_objects_total: The total number of metadata objects + * in the repository after this transaction has completed. + * @metadata_objects_written: The number of metadata objects that + * were written to the repository in this transaction. + * @content_objects_total: The total number of content objects + * in the repository after this transaction has completed. + * @content_objects_written: The number of content objects that + * were written to the repository in this transaction. + * @content_bytes_written: The amount of data added to the repository, + * in bytes, counting only content objects. + * @padding1: reserved + * @padding2: reserved + * @padding3: reserved + * @padding4: reserved + * + * A list of statistics for each transaction that may be + * interesting for reporting purposes. + */ +typedef struct _OstreeRepoTransactionStats OstreeRepoTransactionStats; + +struct _OstreeRepoTransactionStats { + guint metadata_objects_total; + guint metadata_objects_written; + guint content_objects_total; + guint content_objects_written; + guint64 content_bytes_written; + guint devino_cache_hits; + + guint padding1; + guint64 padding2; + guint64 padding3; + guint64 padding4; +}; + +_OSTREE_PUBLIC +GType ostree_repo_transaction_stats_get_type (void); + +_OSTREE_PUBLIC +gboolean ostree_repo_scan_hardlinks (OstreeRepo *self, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_prepare_transaction (OstreeRepo *self, + gboolean *out_transaction_resume, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_commit_transaction (OstreeRepo *self, + OstreeRepoTransactionStats *out_stats, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_abort_transaction (OstreeRepo *self, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_mark_commit_partial (OstreeRepo *self, + const char *checksum, + gboolean is_partial, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_mark_commit_partial_reason (OstreeRepo *self, + const char *checksum, + gboolean is_partial, + OstreeRepoCommitState in_state, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_transaction_set_refspec (OstreeRepo *self, + const char *refspec, + const char *checksum); + +_OSTREE_PUBLIC +void ostree_repo_transaction_set_ref (OstreeRepo *self, + const char *remote, + const char *ref, + const char *checksum); + +_OSTREE_PUBLIC +void ostree_repo_transaction_set_collection_ref (OstreeRepo *self, + const OstreeCollectionRef *ref, + const char *checksum); + +_OSTREE_PUBLIC +gboolean ostree_repo_set_ref_immediate (OstreeRepo *self, + const char *remote, + const char *ref, + const char *checksum, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_set_alias_ref_immediate (OstreeRepo *self, + const char *remote, + const char *ref, + const char *target, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_set_collection_ref_immediate (OstreeRepo *self, + const OstreeCollectionRef *ref, + const char *checksum, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_has_object (OstreeRepo *self, + OstreeObjectType objtype, + const char *checksum, + gboolean *out_have_object, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_metadata (OstreeRepo *self, + OstreeObjectType objtype, + const char *expected_checksum, + GVariant *object, + guchar **out_csum, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_write_metadata_async (OstreeRepo *self, + OstreeObjectType objtype, + const char *expected_checksum, + GVariant *object, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_metadata_finish (OstreeRepo *self, + GAsyncResult *result, + guchar **out_csum, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_content (OstreeRepo *self, + const char *expected_checksum, + GInputStream *object_input, + guint64 length, + guchar **out_csum, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_metadata_trusted (OstreeRepo *self, + OstreeObjectType objtype, + const char *checksum, + GVariant *variant, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_metadata_stream_trusted (OstreeRepo *self, + OstreeObjectType objtype, + const char *checksum, + GInputStream *object_input, + guint64 length, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_content_trusted (OstreeRepo *self, + const char *checksum, + GInputStream *object_input, + guint64 length, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_write_content_async (OstreeRepo *self, + const char *expected_checksum, + GInputStream *object, + guint64 length, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_content_finish (OstreeRepo *self, + GAsyncResult *result, + guchar **out_csum, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_resolve_rev (OstreeRepo *self, + const char *refspec, + gboolean allow_noent, + char **out_rev, + GError **error); + +/** + * OstreeRepoResolveRevExtFlags: + * @OSTREE_REPO_RESOLVE_REV_EXT_NONE: No flags. + * @OSTREE_REPO_RESOLVE_REV_EXT_LOCAL_ONLY: Exclude remote and mirrored refs. Since: 2019.2 + */ +typedef enum { + OSTREE_REPO_RESOLVE_REV_EXT_NONE = 0, + OSTREE_REPO_RESOLVE_REV_EXT_LOCAL_ONLY = (1 << 0), +} OstreeRepoResolveRevExtFlags; + +_OSTREE_PUBLIC +gboolean ostree_repo_resolve_rev_ext (OstreeRepo *self, + const char *refspec, + gboolean allow_noent, + OstreeRepoResolveRevExtFlags flags, + char **out_rev, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_resolve_collection_ref (OstreeRepo *self, + const OstreeCollectionRef *ref, + gboolean allow_noent, + OstreeRepoResolveRevExtFlags flags, + char **out_rev, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_list_refs (OstreeRepo *self, + const char *refspec_prefix, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error); + +/** + * OstreeRepoListRefsExtFlags: + * @OSTREE_REPO_LIST_REFS_EXT_NONE: No flags. + * @OSTREE_REPO_LIST_REFS_EXT_ALIASES: Only list aliases. Since: 2017.10 + * @OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES: Exclude remote refs. Since: 2017.11 + * @OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_MIRRORS: Exclude mirrored refs. Since: 2019.2 + */ +typedef enum { + OSTREE_REPO_LIST_REFS_EXT_NONE = 0, + OSTREE_REPO_LIST_REFS_EXT_ALIASES = (1 << 0), + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES = (1 << 1), + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_MIRRORS = (1 << 2), +} OstreeRepoListRefsExtFlags; + +_OSTREE_PUBLIC +gboolean ostree_repo_list_refs_ext (OstreeRepo *self, + const char *refspec_prefix, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_list_refs (OstreeRepo *self, + const char *remote_name, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_list_collection_refs (OstreeRepo *self, + const char *remote_name, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_load_variant (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + GVariant **out_variant, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_load_variant_if_exists (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + GVariant **out_variant, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_load_commit (OstreeRepo *self, + const char *checksum, + GVariant **out_commit, + OstreeRepoCommitState *out_state, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_load_file (OstreeRepo *self, + const char *checksum, + GInputStream **out_input, + GFileInfo **out_file_info, + GVariant **out_xattrs, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_load_object_stream (OstreeRepo *self, + OstreeObjectType objtype, + const char *checksum, + GInputStream **out_input, + guint64 *out_size, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_query_object_storage_size (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + guint64 *out_size, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_import_object_from (OstreeRepo *self, + OstreeRepo *source, + OstreeObjectType objtype, + const char *checksum, + GCancellable *cancellable, + GError **error); +_OSTREE_PUBLIC +gboolean ostree_repo_import_object_from_with_trust (OstreeRepo *self, + OstreeRepo *source, + OstreeObjectType objtype, + const char *checksum, + gboolean trusted, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_delete_object (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_fsck_object (OstreeRepo *self, + OstreeObjectType objtype, + const char *sha256, + GCancellable *cancellable, + GError **error); + +/** + * OstreeRepoCommitFilterResult: + * @OSTREE_REPO_COMMIT_FILTER_ALLOW: Do commit this object + * @OSTREE_REPO_COMMIT_FILTER_SKIP: Ignore this object + */ +typedef enum { + OSTREE_REPO_COMMIT_FILTER_ALLOW, + OSTREE_REPO_COMMIT_FILTER_SKIP +} OstreeRepoCommitFilterResult; + +/** + * OstreeRepoCommitFilter: + * @repo: Repo + * @path: Path to file + * @file_info: File information + * @user_data: User data + * + * Returns: #OstreeRepoCommitFilterResult saying whether or not to commit this file + */ +typedef OstreeRepoCommitFilterResult (*OstreeRepoCommitFilter) (OstreeRepo *repo, + const char *path, + GFileInfo *file_info, + gpointer user_data); + +/** + * OstreeRepoCommitModifierFlags: + * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_NONE: No special flags + * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS: Do not process extended attributes + * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES: Generate size information. + * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS: Canonicalize permissions for bare-user-only mode. + * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED: Emit an error if configured SELinux policy does not provide a label + * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME: Delete added files/directories after commit; Since: 2017.13 + * @OSTREE_REPO_COMMIT_MODIFIER_FLAGS_DEVINO_CANONICAL: If a devino cache hit is found, skip modifier filters (non-directories only); Since: 2017.14 + */ +typedef enum { + OSTREE_REPO_COMMIT_MODIFIER_FLAGS_NONE = 0, + OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS = (1 << 0), + OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES = (1 << 1), + OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS = (1 << 2), + OSTREE_REPO_COMMIT_MODIFIER_FLAGS_ERROR_ON_UNLABELED = (1 << 3), + OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME = (1 << 4), + OSTREE_REPO_COMMIT_MODIFIER_FLAGS_DEVINO_CANONICAL = (1 << 5), +} OstreeRepoCommitModifierFlags; + +/** + * OstreeRepoCommitModifier: + * + * A structure allowing control over commits. + */ +typedef struct OstreeRepoCommitModifier OstreeRepoCommitModifier; + +_OSTREE_PUBLIC +OstreeRepoCommitModifier *ostree_repo_commit_modifier_new (OstreeRepoCommitModifierFlags flags, + OstreeRepoCommitFilter commit_filter, + gpointer user_data, + GDestroyNotify destroy_notify); + +_OSTREE_PUBLIC +GType ostree_repo_commit_modifier_get_type (void); + +typedef GVariant *(*OstreeRepoCommitModifierXattrCallback) (OstreeRepo *repo, + const char *path, + GFileInfo *file_info, + gpointer user_data); + +_OSTREE_PUBLIC +void ostree_repo_commit_modifier_set_xattr_callback (OstreeRepoCommitModifier *modifier, + OstreeRepoCommitModifierXattrCallback callback, + GDestroyNotify destroy, + gpointer user_data); + +_OSTREE_PUBLIC +void ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier *modifier, + OstreeSePolicy *sepolicy); + +_OSTREE_PUBLIC +gboolean ostree_repo_commit_modifier_set_sepolicy_from_commit (OstreeRepoCommitModifier *modifier, + OstreeRepo *repo, + const char *rev, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_commit_modifier_set_devino_cache (OstreeRepoCommitModifier *modifier, + OstreeRepoDevInoCache *cache); + +_OSTREE_PUBLIC +OstreeRepoCommitModifier *ostree_repo_commit_modifier_ref (OstreeRepoCommitModifier *modifier); +_OSTREE_PUBLIC +void ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_directory_to_mtree (OstreeRepo *self, + GFile *dir, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_dfd_to_mtree (OstreeRepo *self, + int dfd, + const char *path, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GCancellable *cancellable, + GError **error); + + +_OSTREE_PUBLIC +gboolean ostree_repo_write_archive_to_mtree (OstreeRepo *self, + GFile *archive, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + gboolean autocreate_parents, + GCancellable *cancellable, + GError **error); + + +_OSTREE_PUBLIC +gboolean ostree_repo_write_archive_to_mtree_from_fd (OstreeRepo *self, + int fd, + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + gboolean autocreate_parents, + GCancellable *cancellable, + GError **error); + +/** + * OstreeRepoImportArchiveTranslatePathname: + * @repo: Repo + * @stbuf: Stat buffer + * @src_path: Path in the archive + * @user_data: User data + * + * Possibly change a pathname while importing an archive. If %NULL is returned, + * then @src_path will be used unchanged. Otherwise, return a new pathname which + * will be freed via `g_free()`. + * + * This pathname translation will be performed *before* any processing from an + * active `OstreeRepoCommitModifier`. Will be invoked for all directory and file + * types, first with outer directories, then their sub-files and directories. + * + * Note that enabling pathname translation will always override the setting for + * `use_ostree_convention`. + * + * Since: 2017.11 + */ +typedef char *(*OstreeRepoImportArchiveTranslatePathname) (OstreeRepo *repo, + const struct stat *stbuf, + const char *src_path, + gpointer user_data); + +/** + * OstreeRepoImportArchiveOptions: (skip) + * + * An extensible options structure controlling archive import. Ensure that + * you have entirely zeroed the structure, then set just the desired + * options. This is used by ostree_repo_import_archive_to_mtree(). + */ +typedef struct { + guint ignore_unsupported_content : 1; + guint autocreate_parents : 1; + guint use_ostree_convention : 1; + guint callback_with_entry_pathname : 1; + guint reserved : 28; + + guint unused_uint[8]; + OstreeRepoImportArchiveTranslatePathname translate_pathname; + gpointer translate_pathname_user_data; + gpointer unused_ptrs[6]; +} OstreeRepoImportArchiveOptions; + +_OSTREE_PUBLIC +gboolean ostree_repo_import_archive_to_mtree (OstreeRepo *self, + OstreeRepoImportArchiveOptions *opts, + void *archive, /* Really struct archive * */ + OstreeMutableTree *mtree, + OstreeRepoCommitModifier *modifier, + GCancellable *cancellable, + GError **error); + +/** + * OstreeRepoExportArchiveOptions: (skip) + * + * An extensible options structure controlling archive creation. Ensure that + * you have entirely zeroed the structure, then set just the desired + * options. This is used by ostree_repo_export_tree_to_archive(). + */ +typedef struct { + guint disable_xattrs : 1; + guint reserved : 31; + + /* 4 byte hole on 64 bit arches */ + guint64 timestamp_secs; + + guint unused_uint[8]; + + char *path_prefix; + + gpointer unused_ptrs[7]; +} OstreeRepoExportArchiveOptions; + +_OSTREE_PUBLIC +gboolean ostree_repo_export_tree_to_archive (OstreeRepo *self, + OstreeRepoExportArchiveOptions *opts, + OstreeRepoFile *root, + void *archive, /* Really struct archive * */ + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_mtree (OstreeRepo *self, + OstreeMutableTree *mtree, + GFile **out_file, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_commit (OstreeRepo *self, + const char *parent, + const char *subject, + const char *body, + GVariant *metadata, + OstreeRepoFile *root, + char **out_commit, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_commit_with_time (OstreeRepo *self, + const char *parent, + const char *subject, + const char *body, + GVariant *metadata, + OstreeRepoFile *root, + guint64 time, + char **out_commit, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_read_commit_detached_metadata (OstreeRepo *self, + const char *checksum, + GVariant **out_metadata, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_write_commit_detached_metadata (OstreeRepo *self, + const char *checksum, + GVariant *metadata, + GCancellable *cancellable, + GError **error); + +/** + * OstreeRepoCheckoutMode: + * @OSTREE_REPO_CHECKOUT_MODE_NONE: No special options + * @OSTREE_REPO_CHECKOUT_MODE_USER: Ignore uid/gid of files + */ +typedef enum { + OSTREE_REPO_CHECKOUT_MODE_NONE = 0, + OSTREE_REPO_CHECKOUT_MODE_USER = 1 +} OstreeRepoCheckoutMode; + +/** + * OstreeRepoCheckoutOverwriteMode: + * @OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: No special options + * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: When layering checkouts, unlink() and replace existing files, but do not modify existing directories (unless whiteouts are enabled, then directories are replaced) + * @OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: Only add new files/directories + * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: Like UNION_FILES, but error if files are not identical (requires hardlink checkouts) + */ +typedef enum { + OSTREE_REPO_CHECKOUT_OVERWRITE_NONE = 0, + OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1, + OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES = 2, /* Since: 2017.3 */ + OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL = 3, /* Since: 2017.11 */ +} OstreeRepoCheckoutOverwriteMode; + +_OSTREE_PUBLIC +gboolean +ostree_repo_checkout_tree (OstreeRepo *self, + OstreeRepoCheckoutMode mode, + OstreeRepoCheckoutOverwriteMode overwrite_mode, + GFile *destination, + OstreeRepoFile *source, + GFileInfo *source_info, + GCancellable *cancellable, + GError **error); + +/** + * OstreeRepoCheckoutFilterResult: + * @OSTREE_REPO_CHECKOUT_FILTER_ALLOW: Do checkout this object + * @OSTREE_REPO_CHECKOUT_FILTER_SKIP: Ignore this object + * + * Since: 2018.2 + */ +typedef enum { + OSTREE_REPO_CHECKOUT_FILTER_ALLOW, + OSTREE_REPO_CHECKOUT_FILTER_SKIP +} OstreeRepoCheckoutFilterResult; + +/** + * OstreeRepoCheckoutFilter: + * @repo: Repo + * @path: Path to file + * @stbuf: File information + * @user_data: User data + * + * Returns: #OstreeRepoCheckoutFilterResult saying whether or not to checkout this file + * + * Since: 2018.2 + */ +typedef OstreeRepoCheckoutFilterResult (*OstreeRepoCheckoutFilter) (OstreeRepo *repo, + const char *path, + struct stat *stbuf, + gpointer user_data); + +/** + * OstreeRepoCheckoutAtOptions: + * + * An extensible options structure controlling checkout. Ensure that + * you have entirely zeroed the structure, then set just the desired + * options. This is used by ostree_repo_checkout_at() which + * supercedes previous separate enumeration usage in + * ostree_repo_checkout_tree() and ostree_repo_checkout_tree_at(). + */ +typedef struct { + OstreeRepoCheckoutMode mode; + OstreeRepoCheckoutOverwriteMode overwrite_mode; + + gboolean enable_uncompressed_cache; /* Deprecated */ + gboolean enable_fsync; /* Deprecated */ + gboolean process_whiteouts; + gboolean no_copy_fallback; + gboolean force_copy; /* Since: 2017.6 */ + gboolean bareuseronly_dirs; /* Since: 2017.7 */ + gboolean force_copy_zerosized; /* Since: 2018.9 */ + gboolean unused_bools[4]; + /* 4 byte hole on 64 bit */ + + const char *subpath; + + OstreeRepoDevInoCache *devino_to_csum_cache; + + int unused_ints[6]; + gpointer unused_ptrs[3]; + OstreeRepoCheckoutFilter filter; /* Since: 2018.2 */ + gpointer filter_user_data; /* Since: 2018.2 */ + OstreeSePolicy *sepolicy; /* Since: 2017.6 */ + const char *sepolicy_prefix; +} OstreeRepoCheckoutAtOptions; + +_OSTREE_PUBLIC +GType ostree_repo_devino_cache_get_type (void); +_OSTREE_PUBLIC +OstreeRepoDevInoCache *ostree_repo_devino_cache_new (void); +_OSTREE_PUBLIC +OstreeRepoDevInoCache * ostree_repo_devino_cache_ref (OstreeRepoDevInoCache *cache); +_OSTREE_PUBLIC +void ostree_repo_devino_cache_unref (OstreeRepoDevInoCache *cache); + +_OSTREE_PUBLIC +void ostree_repo_checkout_at_options_set_devino (OstreeRepoCheckoutAtOptions *opts, OstreeRepoDevInoCache *cache); + +_OSTREE_PUBLIC +gboolean ostree_repo_checkout_at (OstreeRepo *self, + OstreeRepoCheckoutAtOptions *options, + int destination_dfd, + const char *destination_path, + const char *commit, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_checkout_gc (OstreeRepo *self, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_read_commit (OstreeRepo *self, + const char *ref, + GFile **out_root, + char **out_commit, + GCancellable *cancellable, + GError **error); + +/** + * OstreeRepoListObjectsFlags: + * @OSTREE_REPO_LIST_OBJECTS_LOOSE: List only loose (plain file) objects + * @OSTREE_REPO_LIST_OBJECTS_PACKED: List only packed (compacted into blobs) objects + * @OSTREE_REPO_LIST_OBJECTS_ALL: List all objects + * @OSTREE_REPO_LIST_OBJECTS_NO_PARENTS: Only list objects in this repo, not parents + */ +typedef enum { + OSTREE_REPO_LIST_OBJECTS_LOOSE = (1 << 0), + OSTREE_REPO_LIST_OBJECTS_PACKED = (1 << 1), + OSTREE_REPO_LIST_OBJECTS_ALL = (1 << 2), + OSTREE_REPO_LIST_OBJECTS_NO_PARENTS = (1 << 3), +} OstreeRepoListObjectsFlags; + +/** + * OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE: + * + * b - %TRUE if object is available "loose" + * as - List of pack file checksums in which this object appears + */ +#define OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE (G_VARIANT_TYPE ("(bas)") + +_OSTREE_PUBLIC +gboolean ostree_repo_list_objects (OstreeRepo *self, + OstreeRepoListObjectsFlags flags, + GHashTable **out_objects, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_list_commit_objects_starting_with ( OstreeRepo *self, + const char *start, + GHashTable **out_commits, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_list_static_delta_names (OstreeRepo *self, + GPtrArray **out_deltas, + GCancellable *cancellable, + GError **error); + +/** + * OstreeStaticDeltaGenerateOpt: + * @OSTREE_STATIC_DELTA_GENERATE_OPT_LOWLATENCY: Optimize for speed of delta creation over space + * @OSTREE_STATIC_DELTA_GENERATE_OPT_MAJOR: Optimize for delta size (may be very slow) + * + * Parameters controlling optimization of static deltas. + */ +typedef enum { + OSTREE_STATIC_DELTA_GENERATE_OPT_LOWLATENCY, + OSTREE_STATIC_DELTA_GENERATE_OPT_MAJOR +} OstreeStaticDeltaGenerateOpt; + +_OSTREE_PUBLIC +gboolean ostree_repo_static_delta_generate (OstreeRepo *self, + OstreeStaticDeltaGenerateOpt opt, + const char *from, + const char *to, + GVariant *metadata, + GVariant *params, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_static_delta_execute_offline (OstreeRepo *self, + GFile *dir_or_file, + gboolean skip_validation, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +GHashTable *ostree_repo_traverse_new_reachable (void); + +_OSTREE_PUBLIC +GHashTable *ostree_repo_traverse_new_parents (void); + +_OSTREE_PUBLIC +char ** ostree_repo_traverse_parents_get_commits (GHashTable *parents, GVariant *object); + +_OSTREE_PUBLIC +gboolean ostree_repo_traverse_commit (OstreeRepo *repo, + const char *commit_checksum, + int maxdepth, + GHashTable **out_reachable, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_traverse_commit_union (OstreeRepo *repo, + const char *commit_checksum, + int maxdepth, + GHashTable *inout_reachable, + GCancellable *cancellable, + GError **error); +_OSTREE_PUBLIC +gboolean ostree_repo_traverse_commit_union_with_parents (OstreeRepo *repo, + const char *commit_checksum, + int maxdepth, + GHashTable *inout_reachable, + GHashTable *inout_parents, + GCancellable *cancellable, + GError **error); + +struct _OstreeRepoCommitTraverseIter { + gboolean initialized; + /* 4 byte hole on 64 bit */ + gpointer dummy[10]; + char dummy_checksum_data[(OSTREE_SHA256_STRING_LEN+1)*2]; +}; + +typedef struct _OstreeRepoCommitTraverseIter OstreeRepoCommitTraverseIter; + +typedef enum { + OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE = (1 << 0) +} OstreeRepoCommitTraverseFlags; + +_OSTREE_PUBLIC +gboolean +ostree_repo_commit_traverse_iter_init_commit (OstreeRepoCommitTraverseIter *iter, + OstreeRepo *repo, + GVariant *commit, + OstreeRepoCommitTraverseFlags flags, + GError **error); + +_OSTREE_PUBLIC +gboolean +ostree_repo_commit_traverse_iter_init_dirtree (OstreeRepoCommitTraverseIter *iter, + OstreeRepo *repo, + GVariant *dirtree, + OstreeRepoCommitTraverseFlags flags, + GError **error); + +typedef enum { + OSTREE_REPO_COMMIT_ITER_RESULT_ERROR, + OSTREE_REPO_COMMIT_ITER_RESULT_END, + OSTREE_REPO_COMMIT_ITER_RESULT_FILE, + OSTREE_REPO_COMMIT_ITER_RESULT_DIR +} OstreeRepoCommitIterResult; + +_OSTREE_PUBLIC +OstreeRepoCommitIterResult ostree_repo_commit_traverse_iter_next (OstreeRepoCommitTraverseIter *iter, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_commit_traverse_iter_get_file (OstreeRepoCommitTraverseIter *iter, + char **out_name, + char **out_checksum); + +_OSTREE_PUBLIC +void ostree_repo_commit_traverse_iter_get_dir (OstreeRepoCommitTraverseIter *iter, + char **out_name, + char **out_content_checksum, + char **out_meta_checksum); + +_OSTREE_PUBLIC +void ostree_repo_commit_traverse_iter_clear (OstreeRepoCommitTraverseIter *iter); + +_OSTREE_PUBLIC +void ostree_repo_commit_traverse_iter_cleanup (void *p); + +#define ostree_cleanup_repo_commit_traverse_iter __attribute__ ((cleanup(ostree_repo_commit_traverse_iter_cleanup))) + +/** + * OstreeRepoPruneFlags: + * @OSTREE_REPO_PRUNE_FLAGS_NONE: No special options for pruning + * @OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE: Don't actually delete objects + * @OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY: Do not traverse individual commit objects, only follow refs + */ +typedef enum { + OSTREE_REPO_PRUNE_FLAGS_NONE = 0, + OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE = (1 << 0), + OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY = (1 << 1), +} OstreeRepoPruneFlags; + +_OSTREE_PUBLIC +gboolean +ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_prune (OstreeRepo *self, + OstreeRepoPruneFlags flags, + gint depth, + gint *out_objects_total, + gint *out_objects_pruned, + guint64 *out_pruned_object_size_total, + GCancellable *cancellable, + GError **error); + +struct _OstreeRepoPruneOptions { + OstreeRepoPruneFlags flags; + + /* 4 byte hole on 64 bit */ + + GHashTable *reachable; /* Set (object names) */ + + gboolean unused_bools[6]; + int unused_ints[6]; + gpointer unused_ptrs[7]; +}; + +typedef struct _OstreeRepoPruneOptions OstreeRepoPruneOptions; + +_OSTREE_PUBLIC +gboolean +ostree_repo_traverse_reachable_refs (OstreeRepo *self, + guint depth, + GHashTable *reachable, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_prune_from_reachable (OstreeRepo *self, + OstreeRepoPruneOptions *options, + gint *out_objects_total, + gint *out_objects_pruned, + guint64 *out_pruned_object_size_total, + GCancellable *cancellable, + GError **error); + +/** + * OstreeRepoPullFlags: + * @OSTREE_REPO_PULL_FLAGS_NONE: No special options for pull + * @OSTREE_REPO_PULL_FLAGS_MIRROR: Write out refs suitable for mirrors and fetch all refs if none requested + * @OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY: Fetch only the commit metadata + * @OSTREE_REPO_PULL_FLAGS_UNTRUSTED: Do verify checksums of local (filesystem-accessible) repositories (defaults on for HTTP) + * @OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES: Since 2017.7. Reject writes of content objects with modes outside of 0775. + * @OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP: Don't verify checksums of objects HTTP repositories (Since: 2017.12) + */ +typedef enum { + OSTREE_REPO_PULL_FLAGS_NONE, + OSTREE_REPO_PULL_FLAGS_MIRROR = (1 << 0), + OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY = (1 << 1), + OSTREE_REPO_PULL_FLAGS_UNTRUSTED = (1 << 2), + OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES = (1 << 3), + OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP = (1 << 4), +} OstreeRepoPullFlags; + +_OSTREE_PUBLIC +gboolean ostree_repo_pull (OstreeRepo *self, + const char *remote_name, + char **refs_to_fetch, + OstreeRepoPullFlags flags, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean +ostree_repo_pull_one_dir (OstreeRepo *self, + const char *remote_name, + const char *dir_to_pull, + char **refs_to_fetch, + OstreeRepoPullFlags flags, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_pull_with_options (OstreeRepo *self, + const char *remote_name_or_baseurl, + GVariant *options, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_find_remotes_async (OstreeRepo *self, + const OstreeCollectionRef * const *refs, + GVariant *options, + OstreeRepoFinder **finders, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +_OSTREE_PUBLIC +OstreeRepoFinderResult **ostree_repo_find_remotes_finish (OstreeRepo *self, + GAsyncResult *result, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_pull_from_remotes_async (OstreeRepo *self, + const OstreeRepoFinderResult * const *results, + GVariant *options, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +_OSTREE_PUBLIC +gboolean ostree_repo_pull_from_remotes_finish (OstreeRepo *self, + GAsyncResult *result, + GError **error); + +_OSTREE_PUBLIC +OstreeRemote *ostree_repo_resolve_keyring_for_collection (OstreeRepo *self, + const gchar *collection_id, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_list_collection_refs (OstreeRepo *self, + const char *match_collection_id, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress, + gpointer user_data); + +_OSTREE_PUBLIC +gboolean ostree_repo_sign_commit (OstreeRepo *self, + const gchar *commit_checksum, + const gchar *key_id, + const gchar *homedir, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_sign_delta (OstreeRepo *self, + const gchar *from_commit, + const gchar *to_commit, + const gchar *key_id, + const gchar *homedir, + GCancellable *cancellable, + GError **error); + + +_OSTREE_PUBLIC +gboolean ostree_repo_verify_commit (OstreeRepo *self, + const gchar *commit_checksum, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_get_gpg_verify (OstreeRepo *self, + const char *name, + gboolean *out_gpg_verify, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_remote_get_gpg_verify_summary (OstreeRepo *self, + const char *name, + gboolean *out_gpg_verify_summary, + GError **error); +_OSTREE_PUBLIC +gboolean ostree_repo_remote_gpg_import (OstreeRepo *self, + const char *name, + GInputStream *source_stream, + const char * const *key_ids, + guint *out_imported, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_add_gpg_signature_summary (OstreeRepo *self, + const gchar **key_id, + const gchar *homedir, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_append_gpg_signature (OstreeRepo *self, + const gchar *commit_checksum, + GBytes *signature_bytes, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeGpgVerifyResult * ostree_repo_verify_commit_ext (OstreeRepo *self, + const gchar *commit_checksum, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeGpgVerifyResult * +ostree_repo_verify_commit_for_remote (OstreeRepo *self, + const gchar *commit_checksum, + const gchar *remote_name, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeGpgVerifyResult * ostree_repo_gpg_verify_data (OstreeRepo *self, + const gchar *remote_name, + GBytes *data, + GBytes *signatures, + GFile *keyringdir, + GFile *extra_keyring, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeGpgVerifyResult * ostree_repo_verify_summary (OstreeRepo *self, + const char *remote_name, + GBytes *summary, + GBytes *signatures, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_repo_regenerate_summary (OstreeRepo *self, + GVariant *additional_metadata, + GCancellable *cancellable, + GError **error); + +/** + * OSTREE_REPO_METADATA_REF: + * + * The name of a ref which is used to store metadata for the entire repository, + * such as its expected update time (`ostree.summary.expires`), name, or new + * GPG keys. Metadata is stored on contentless commits in the ref, and hence is + * signed with the commits. + * + * This supersedes the additional metadata dictionary in the `summary` file + * (see ostree_repo_regenerate_summary()), as the use of a ref means that the + * metadata for multiple upstream repositories can be included in a single mirror + * repository, disambiguating the refs using collection IDs. In order to support + * peer to peer redistribution of repository metadata, repositories must set a + * collection ID (ostree_repo_set_collection_id()). + * + * Users of OSTree may place arbitrary metadata in commits on this ref, but the + * keys must be namespaced by product or developer. For example, + * `exampleos.end-of-life`. The `ostree.` prefix is reserved. + * + * Since: 2018.6 + */ +#define OSTREE_REPO_METADATA_REF "ostree-metadata" + +/** + * OSTREE_META_KEY_DEPLOY_COLLECTION_ID: + * + * GVariant type `s`. This key can be used in the repo metadata which is stored + * in OSTREE_REPO_METADATA_REF as well as in the summary. The semantics of this + * are that the remote repository wants clients to update their remote config + * to add this collection ID (clients can't do P2P operations involving a + * remote without a collection ID configured on it, even if one is configured + * on the server side). Clients must never change or remove a collection ID + * already set in their remote config. + * + * Currently, OSTree does not implement changing a remote config based on this + * key, but it may do so in a later release, and until then clients such as + * Flatpak may implement it. + * + * This is a replacement for the similar metadata key implemented by flatpak, + * `xa.collection-id`, which is now deprecated as clients which supported it had + * bugs with their P2P implementations. + * + * Since: 2018.9 + */ +#define OSTREE_META_KEY_DEPLOY_COLLECTION_ID "ostree.deploy-collection-id" + +G_END_DECLS + + +/* Include here as the functions defined before should not depend on anything which + is defined in -deprecated.h. */ +#include "ostree-repo-deprecated.h" diff --git a/src/libostree/ostree-rollsum.c b/src/libostree/ostree-rollsum.c new file mode 100644 index 0000000..74033e3 --- /dev/null +++ b/src/libostree/ostree-rollsum.c @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2015 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include "ostree-rollsum.h" +#include "libglnx.h" +#include "bupsplit.h" + +#define ROLLSUM_BLOB_MAX (8192*4) + +static GHashTable * +rollsum_chunks_crc32 (GBytes *bytes) +{ + gsize start = 0; + gboolean rollsum_end = FALSE; + GHashTable *ret_rollsums = NULL; + const guint8 *buf; + gsize buflen; + gsize remaining; + + ret_rollsums = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_ptr_array_unref); + + buf = g_bytes_get_data (bytes, &buflen); + + remaining = buflen; + while (remaining > 0) + { + int offset, bits; + + if (!rollsum_end) + { + offset = bupsplit_find_ofs (buf + start, MIN(G_MAXINT32, remaining), &bits); + if (offset == 0) + { + rollsum_end = TRUE; + offset = MIN(ROLLSUM_BLOB_MAX, remaining); + } + else if (offset > ROLLSUM_BLOB_MAX) + offset = ROLLSUM_BLOB_MAX; + } + else + offset = MIN(ROLLSUM_BLOB_MAX, remaining); + + /* Use zlib's crc32 */ + { guint32 crc = crc32 (0L, NULL, 0); + GVariant *val; + GPtrArray *matches; + + crc = crc32 (crc, buf, offset); + + val = g_variant_ref_sink (g_variant_new ("(utt)", crc, (guint64) start, (guint64)offset)); + matches = g_hash_table_lookup (ret_rollsums, GUINT_TO_POINTER (crc)); + if (!matches) + { + matches = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); + g_hash_table_insert (ret_rollsums, GUINT_TO_POINTER (crc), matches); + } + g_ptr_array_add (matches, val); + } + + start += offset; + remaining -= offset; + } + + return ret_rollsums; +} + +static gint +compare_matches (const void *app, + const void *bpp) +{ + GVariant **avpp = (GVariant**)app; + GVariant *a = *avpp; + GVariant **bvpp = (GVariant**)bpp; + GVariant *b = *bvpp; + guint64 a_start, b_start; + + g_variant_get_child (a, 2, "t", &a_start); + g_variant_get_child (b, 2, "t", &b_start); + + g_assert_cmpint (a_start, !=, b_start); + + if (a_start < b_start) + return -1; + return 1; +} + +OstreeRollsumMatches * +_ostree_compute_rollsum_matches (GBytes *from, + GBytes *to) +{ + OstreeRollsumMatches *ret_rollsum = NULL; + g_autoptr(GHashTable) from_rollsum = NULL; + g_autoptr(GHashTable) to_rollsum = NULL; + g_autoptr(GPtrArray) matches = NULL; + const guint8 *from_buf; + gsize from_len; + const guint8 *to_buf; + gsize to_len; + gpointer hkey, hvalue; + GHashTableIter hiter; + + ret_rollsum = g_new0 (OstreeRollsumMatches, 1); + + matches = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); + + from_buf = g_bytes_get_data (from, &from_len); + to_buf = g_bytes_get_data (to, &to_len); + + from_rollsum = rollsum_chunks_crc32 (from); + to_rollsum = rollsum_chunks_crc32 (to); + + g_hash_table_iter_init (&hiter, to_rollsum); + while (g_hash_table_iter_next (&hiter, &hkey, &hvalue)) + { + GPtrArray *to_chunks = hvalue; + GPtrArray *from_chunks; + + from_chunks = g_hash_table_lookup (from_rollsum, hkey); + if (from_chunks != NULL) + { + guint i; + + ret_rollsum->crcmatches++; + + for (i = 0; i < to_chunks->len; i++) + { + GVariant *to_chunk = to_chunks->pdata[i]; + guint64 to_start, to_offset; + guint32 tocrc; + guint j; + + g_variant_get (to_chunk, "(utt)", &tocrc, &to_start, &to_offset); + + for (j = 0; j < from_chunks->len; j++) + { + GVariant *from_chunk = from_chunks->pdata[j]; + guint32 fromcrc; + guint64 from_start, from_offset; + + g_variant_get (from_chunk, "(utt)", &fromcrc, &from_start, &from_offset); + + g_assert (fromcrc == tocrc); + + /* Same crc32 but different length, skip it. */ + if (to_offset != from_offset) + continue; + + /* Rsync uses a cryptographic checksum, but let's be + * very conservative here and just memcmp. + */ + if (memcmp (from_buf + from_start, to_buf + to_start, to_offset) == 0) + { + GVariant *match = g_variant_new ("(uttt)", fromcrc, to_offset, to_start, from_start); + ret_rollsum->bufmatches++; + ret_rollsum->match_size += to_offset; + g_ptr_array_add (matches, g_variant_ref_sink (match)); + break; /* Don't need any more matches */ + } + } + } + } + + ret_rollsum->total += to_chunks->len; + } + + g_ptr_array_sort (matches, compare_matches); + + ret_rollsum->from_rollsums = from_rollsum; from_rollsum = NULL; + ret_rollsum->to_rollsums = to_rollsum; to_rollsum = NULL; + ret_rollsum->matches = matches; matches = NULL; + + return ret_rollsum; +} + +void +_ostree_rollsum_matches_free (OstreeRollsumMatches *rollsum) +{ + g_hash_table_unref (rollsum->to_rollsums); + g_hash_table_unref (rollsum->from_rollsums); + g_ptr_array_unref (rollsum->matches); + g_free (rollsum); +} diff --git a/src/libostree/ostree-rollsum.h b/src/libostree/ostree-rollsum.h new file mode 100644 index 0000000..6f8ca53 --- /dev/null +++ b/src/libostree/ostree-rollsum.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include "libglnx.h" + +G_BEGIN_DECLS + +typedef struct { + GHashTable *from_rollsums; + GHashTable *to_rollsums; + guint crcmatches; + guint bufmatches; + guint total; + guint64 match_size; + GPtrArray *matches; +} OstreeRollsumMatches; + +OstreeRollsumMatches * +_ostree_compute_rollsum_matches (GBytes *from, + GBytes *to); + +void _ostree_rollsum_matches_free (OstreeRollsumMatches *rollsum); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeRollsumMatches, _ostree_rollsum_matches_free) + +G_END_DECLS diff --git a/src/libostree/ostree-sepolicy-private.h b/src/libostree/ostree-sepolicy-private.h new file mode 100644 index 0000000..980f258 --- /dev/null +++ b/src/libostree/ostree-sepolicy-private.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-types.h" + +G_BEGIN_DECLS + +typedef struct { + gboolean initialized; +} OstreeSepolicyFsCreatecon; + +void _ostree_sepolicy_fscreatecon_clear (OstreeSepolicyFsCreatecon *con); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeSepolicyFsCreatecon, _ostree_sepolicy_fscreatecon_clear) + +gboolean _ostree_sepolicy_preparefscreatecon (OstreeSepolicyFsCreatecon *con, + OstreeSePolicy *self, + const char *path, + guint32 mode, + GError **error); + +GVariant *_ostree_filter_selinux_xattr (GVariant *xattrs); + +G_END_DECLS diff --git a/src/libostree/ostree-sepolicy.c b/src/libostree/ostree-sepolicy.c new file mode 100644 index 0000000..e6b9a0e --- /dev/null +++ b/src/libostree/ostree-sepolicy.c @@ -0,0 +1,734 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#ifdef HAVE_SELINUX +#include +#include +#endif + +#include "otutil.h" + +#include "ostree-sepolicy.h" +#include "ostree-sepolicy-private.h" +#include "ostree-bootloader-uboot.h" +#include "ostree-bootloader-syslinux.h" + +/** + * SECTION:ostree-sepolicy + * @title: SELinux policy management + * @short_description: Read SELinux policy and manage filesystem labels + * + * A #OstreeSePolicy object can load the SELinux policy from a given + * root and perform labeling. + */ +struct OstreeSePolicy { + GObject parent; + + int rootfs_dfd; + int rootfs_dfd_owned; + GFile *path; + +#ifdef HAVE_SELINUX + GFile *selinux_policy_root; + struct selabel_handle *selinux_hnd; + char *selinux_policy_name; + char *selinux_policy_csum; +#endif +}; + +typedef struct { + GObjectClass parent_class; +} OstreeSePolicyClass; + +static void initable_iface_init (GInitableIface *initable_iface); + +enum { + PROP_0, + + PROP_PATH, + PROP_ROOTFS_DFD +}; + +G_DEFINE_TYPE_WITH_CODE (OstreeSePolicy, ostree_sepolicy, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)) + +static void +ostree_sepolicy_finalize (GObject *object) +{ + OstreeSePolicy *self = OSTREE_SEPOLICY (object); + + g_clear_object (&self->path); + if (self->rootfs_dfd_owned != -1) + (void) close (self->rootfs_dfd_owned); +#ifdef HAVE_SELINUX + g_clear_object (&self->selinux_policy_root); + g_clear_pointer (&self->selinux_policy_name, g_free); + g_clear_pointer (&self->selinux_policy_csum, g_free); + if (self->selinux_hnd) + { + selabel_close (self->selinux_hnd); + self->selinux_hnd = NULL; + } +#endif + + G_OBJECT_CLASS (ostree_sepolicy_parent_class)->finalize (object); +} + +static void +ostree_sepolicy_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeSePolicy *self = OSTREE_SEPOLICY (object); + + switch (prop_id) + { + case PROP_PATH: + { + GFile *path = g_value_get_object (value); + if (path) + { + /* Canonicalize */ + self->path = g_file_new_for_path (gs_file_get_path_cached (path)); + g_assert_cmpint (self->rootfs_dfd, ==, -1); + } + } + break; + case PROP_ROOTFS_DFD: + { + int fd = g_value_get_int (value); + if (fd != -1) + { + g_assert (self->path == NULL); + self->rootfs_dfd = fd; + } + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_sepolicy_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeSePolicy *self = OSTREE_SEPOLICY (object); + + switch (prop_id) + { + case PROP_PATH: + g_value_set_object (value, self->path); + break; + case PROP_ROOTFS_DFD: + g_value_set_int (value, self->rootfs_dfd); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_sepolicy_constructed (GObject *object) +{ + OstreeSePolicy *self = OSTREE_SEPOLICY (object); + + g_assert (self->path != NULL || self->rootfs_dfd != -1); + + G_OBJECT_CLASS (ostree_sepolicy_parent_class)->constructed (object); +} + +static void +ostree_sepolicy_class_init (OstreeSePolicyClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = ostree_sepolicy_constructed; + object_class->get_property = ostree_sepolicy_get_property; + object_class->set_property = ostree_sepolicy_set_property; + object_class->finalize = ostree_sepolicy_finalize; + + g_object_class_install_property (object_class, + PROP_PATH, + g_param_spec_object ("path", + "", + "", + G_TYPE_FILE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_ROOTFS_DFD, + g_param_spec_int ("rootfs-dfd", + "", "", + -1, G_MAXINT, -1, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + +} + +#ifdef HAVE_SELINUX + +/* Find the latest policy file in our root and return its checksum. */ +static gboolean +get_policy_checksum (char **out_csum, + GCancellable *cancellable, + GError **error) +{ + const char *binary_policy_path = selinux_binary_policy_path (); + const char *binfile_prefix = glnx_basename (binary_policy_path); + g_autofree char *bindir_path = g_path_get_dirname (binary_policy_path); + + + g_autofree char *best_policy = NULL; + int best_version = 0; + + glnx_autofd int bindir_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, bindir_path, TRUE, &bindir_dfd, error)) + return FALSE; + + g_auto(GLnxDirFdIterator) dfd_iter = { 0,}; + if (!glnx_dirfd_iterator_init_at (bindir_dfd, ".", FALSE, &dfd_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent = NULL; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, + cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (dent->d_type == DT_REG) + { + /* We could probably save a few hundred nanoseconds if we accept that + * the prefix will always be "policy" and hardcode that in a static + * compile-once GRegex... But picture how exciting it'd be if it *did* + * somehow change; there would be cheers & slow-mo high-fives at the + * sight of our code not breaking. Is that hope not worth a fraction + * of a millisecond? I believe it is... or maybe I'm just lazy. */ + g_autofree char *regex = g_strdup_printf ("^\\Q%s\\E\\.[0-9]+$", + binfile_prefix); + + /* we could use match groups to extract the version, but mehhh, we + * already have the prefix on hand */ + if (g_regex_match_simple (regex, dent->d_name, 0, 0)) + { + int version = /* do +1 for the period */ + (int)g_ascii_strtoll (dent->d_name + strlen (binfile_prefix)+1, + NULL, 10); + g_assert (version > 0); + + if (version > best_version) + { + best_version = version; + g_free (best_policy); + best_policy = g_strdup (dent->d_name); + } + } + } + } + + if (!best_policy) + return glnx_throw (error, "Could not find binary policy file"); + + *out_csum = ot_checksum_file_at (bindir_dfd, best_policy, G_CHECKSUM_SHA256, + cancellable, error); + if (*out_csum == NULL) + return FALSE; + + return TRUE; +} + +#endif + + +/* Workaround for http://marc.info/?l=selinux&m=149323809332417&w=2 */ +#ifdef HAVE_SELINUX +static gboolean +cached_is_selinux_enabled (void) +{ + static gsize initialized; + static gboolean cached_enabled; + if (g_once_init_enter (&initialized)) + { + cached_enabled = is_selinux_enabled () == 1; + g_once_init_leave (&initialized, 1); + } + return cached_enabled; +} +#endif + +static gboolean +initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_SELINUX + OstreeSePolicy *self = OSTREE_SEPOLICY (initable); + gboolean enabled = FALSE; + g_autofree char *policytype = NULL; + const char *selinux_prefix = "SELINUX="; + const char *selinuxtype_prefix = "SELINUXTYPE="; + + /* First thing here, call is_selinux_enabled() to prime the cache. See the + * link above for more information why. + */ + (void) cached_is_selinux_enabled (); + + /* TODO - use this below */ + g_autoptr(GFile) path = NULL; + if (self->rootfs_dfd != -1) + path = ot_fdrel_to_gfile (self->rootfs_dfd, "."); + else if (self->path) + { + path = g_object_ref (self->path); +#if 0 + /* TODO - use this below */ + if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->path), TRUE, + &self->rootfs_dfd_owned, error)) + return FALSE; + self->rootfs_dfd = self->rootfs_dfd_owned; +#endif + } + else + g_assert_not_reached (); + + g_autoptr(GFile) etc_selinux_dir = g_file_resolve_relative_path (path, "etc/selinux"); + if (!g_file_query_exists (etc_selinux_dir, NULL)) + { + g_object_unref (etc_selinux_dir); + etc_selinux_dir = g_file_resolve_relative_path (path, "usr/etc/selinux"); + } + + g_autoptr(GFile) policy_config_path = g_file_get_child (etc_selinux_dir, "config"); + g_autoptr(GFile) policy_root = NULL; + if (g_file_query_exists (policy_config_path, NULL)) + { + g_autoptr(GFileInputStream) filein = g_file_read (policy_config_path, cancellable, error); + + if (!filein) + return FALSE; + + g_autoptr(GDataInputStream) datain = g_data_input_stream_new ((GInputStream*)filein); + + while (TRUE) + { + gsize len; + g_autoptr(GError) temp_error = NULL; + g_autofree char *line = g_data_input_stream_read_line_utf8 (datain, &len, + cancellable, &temp_error); + + if (temp_error) + return g_propagate_error (error, g_steal_pointer (&temp_error)), FALSE; + + if (!line) + break; + + if (g_str_has_prefix (line, selinuxtype_prefix)) + { + policytype = g_strstrip (g_strdup (line + strlen (selinuxtype_prefix))); + policy_root = g_file_get_child (etc_selinux_dir, policytype); + } + else if (g_str_has_prefix (line, selinux_prefix)) + { + const char *enabled_str = line + strlen (selinux_prefix); + if (g_ascii_strncasecmp (enabled_str, "enforcing", strlen ("enforcing")) == 0 || + g_ascii_strncasecmp (enabled_str, "permissive", strlen ("permissive")) == 0) + enabled = TRUE; + } + } + } + + if (enabled) + { + const char *policy_rootpath = gs_file_get_path_cached (policy_root); + + g_setenv ("LIBSELINUX_DISABLE_PCRE_PRECOMPILED", "1", FALSE); + if (selinux_set_policy_root (policy_rootpath) != 0) + return glnx_throw_errno_prefix (error, "selinux_set_policy_root(%s)", policy_rootpath); + + self->selinux_hnd = selabel_open (SELABEL_CTX_FILE, NULL, 0); + if (!self->selinux_hnd) + return glnx_throw_errno_prefix (error, "With policy root '%s': selabel_open(SELABEL_CTX_FILE)", + policy_rootpath); + + char *con = NULL; + if (selabel_lookup_raw (self->selinux_hnd, &con, "/", 0755) != 0) + return glnx_throw_errno_prefix (error, "With policy root '%s': Failed to look up context of /", + policy_rootpath); + freecon (con); + + if (!get_policy_checksum (&self->selinux_policy_csum, cancellable, error)) + return glnx_prefix_error (error, "While calculating SELinux checksum"); + + self->selinux_policy_name = g_steal_pointer (&policytype); + self->selinux_policy_root = g_object_ref (etc_selinux_dir); + } + +#endif + return TRUE; +} + +static void +ostree_sepolicy_init (OstreeSePolicy *self) +{ + self->rootfs_dfd = -1; + self->rootfs_dfd_owned = -1; +} + +static void +initable_iface_init (GInitableIface *initable_iface) +{ + initable_iface->init = initable_init; +} + +/** + * ostree_sepolicy_new: + * @path: Path to a root directory + * @cancellable: Cancellable + * @error: Error + * + * Returns: (transfer full): An accessor object for SELinux policy in root located at @path + */ +OstreeSePolicy* +ostree_sepolicy_new (GFile *path, + GCancellable *cancellable, + GError **error) +{ + return g_initable_new (OSTREE_TYPE_SEPOLICY, cancellable, error, "path", path, NULL); +} + +/** + * ostree_sepolicy_new_at: + * @rootfs_dfd: Directory fd for rootfs (will not be cloned) + * @cancellable: Cancellable + * @error: Error + * + * Returns: (transfer full): An accessor object for SELinux policy in root located at @rootfs_dfd + * + * Since: 2017.4 + */ +OstreeSePolicy* +ostree_sepolicy_new_at (int rootfs_dfd, + GCancellable *cancellable, + GError **error) +{ + return g_initable_new (OSTREE_TYPE_SEPOLICY, cancellable, error, "rootfs-dfd", rootfs_dfd, NULL); +} + +/** + * ostree_sepolicy_get_path: + * @self: + * + * Returns: (transfer none): Path to rootfs + */ +GFile * +ostree_sepolicy_get_path (OstreeSePolicy *self) +{ + return self->path; +} + +/** + * ostree_sepolicy_get_name: + * @self: + * + * Returns: (transfer none): Type of current policy + */ +const char * +ostree_sepolicy_get_name (OstreeSePolicy *self) +{ +#ifdef HAVE_SELINUX + return self->selinux_policy_name; +#else + return NULL; +#endif +} + +/** + * ostree_sepolicy_get_csum: + * @self: + * + * Returns: (transfer none): Checksum of current policy + * + * Since: 2016.5 + */ +const char * +ostree_sepolicy_get_csum (OstreeSePolicy *self) +{ +#ifdef HAVE_SELINUX + return self->selinux_policy_csum; +#else + return NULL; +#endif +} + +/** + * ostree_sepolicy_get_label: + * @self: Self + * @relpath: Path + * @unix_mode: Unix mode + * @out_label: (allow-none) (out) (transfer full): Return location for security context + * @cancellable: Cancellable + * @error: Error + * + * Store in @out_label the security context for the given @relpath and + * mode @unix_mode. If the policy does not specify a label, %NULL + * will be returned. + */ +gboolean +ostree_sepolicy_get_label (OstreeSePolicy *self, + const char *relpath, + guint32 unix_mode, + char **out_label, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_SELINUX + /* Early return if no policy */ + if (!self->selinux_hnd) + return TRUE; + + /* http://marc.info/?l=selinux&m=149082134430052&w=2 + * https://github.com/ostreedev/ostree/pull/768 + */ + if (strcmp (relpath, "/proc") == 0) + relpath = "/mnt"; + + char *con = NULL; + int res = selabel_lookup_raw (self->selinux_hnd, &con, relpath, unix_mode); + if (res != 0) + { + if (errno == ENOENT) + *out_label = NULL; + else + return glnx_throw_errno_prefix (error, "selabel_lookup"); + } + else + { + /* Ensure we consistently allocate with g_malloc */ + *out_label = g_strdup (con); + freecon (con); + } + +#endif + return TRUE; +} + +/** + * ostree_sepolicy_restorecon: + * @self: Self + * @path: Path string to use for policy lookup + * @info: (allow-none): File attributes + * @target: Physical path to target file + * @flags: Flags controlling behavior + * @out_new_label: (allow-none) (out): New label, or %NULL if unchanged + * @cancellable: Cancellable + * @error: Error + * + * Reset the security context of @target based on the SELinux policy. + */ +gboolean +ostree_sepolicy_restorecon (OstreeSePolicy *self, + const char *path, + GFileInfo *info, + GFile *target, + OstreeSePolicyRestoreconFlags flags, + char **out_new_label, + GCancellable *cancellable, + GError **error) +{ +#ifdef HAVE_SELINUX + g_autoptr(GFileInfo) src_info = NULL; + if (info != NULL) + src_info = g_object_ref (info); + else + { + src_info = g_file_query_info (target, "unix::mode", + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!src_info) + return FALSE; + } + + gboolean do_relabel = TRUE; + if (flags & OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING) + { + char *existing_con = NULL; + if (lgetfilecon_raw (gs_file_get_path_cached (target), &existing_con) > 0 + && existing_con) + { + do_relabel = FALSE; + freecon (existing_con); + } + } + + g_autofree char *label = NULL; + if (do_relabel) + { + if (!ostree_sepolicy_get_label (self, path, + g_file_info_get_attribute_uint32 (src_info, "unix::mode"), + &label, + cancellable, error)) + return FALSE; + + if (!label) + { + if (!(flags & OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL)) + return glnx_throw (error, "No label found for '%s'", path); + } + else + { + if (lsetfilecon (gs_file_get_path_cached (target), label) < 0) + return glnx_throw_errno_prefix (error, "lsetfilecon"); + } + } + + if (out_new_label) + *out_new_label = g_steal_pointer (&label); +#endif + return TRUE; +} + +/** + * ostree_sepolicy_setfscreatecon: + * @self: Policy + * @path: Use this path to determine a label + * @mode: Used along with @path + * @error: Error + * + */ +gboolean +ostree_sepolicy_setfscreatecon (OstreeSePolicy *self, + const char *path, + guint32 mode, + GError **error) +{ +#ifdef HAVE_SELINUX + g_autofree char *label = NULL; + + /* setfscreatecon() will bomb out if the host has SELinux disabled, + * but we're enabled for the target system. This is kind of a + * broken scenario...for now, we'll silently ignore the label + * request. To correctly handle the case of disabled host but + * enabled target will require nontrivial work. + */ + if (!cached_is_selinux_enabled ()) + return TRUE; + + if (!ostree_sepolicy_get_label (self, path, mode, &label, NULL, error)) + return FALSE; + + if (setfscreatecon_raw (label) != 0) + return glnx_throw_errno_prefix (error, "setfscreatecon"); + +#endif + return TRUE; +} + +/** + * ostree_sepolicy_fscreatecon_cleanup: + * @unused: Not used, just in case you didn't infer that from the parameter name + * + * Cleanup function for ostree_sepolicy_setfscreatecon(). + */ +void +ostree_sepolicy_fscreatecon_cleanup (void **unused) +{ +#ifdef HAVE_SELINUX + setfscreatecon (NULL); +#endif +} + +/* Currently private copy of the older sepolicy/fscreatecon API with a nicer + * g_auto() cleanup. May be made public later. + */ +gboolean +_ostree_sepolicy_preparefscreatecon (OstreeSepolicyFsCreatecon *con, + OstreeSePolicy *self, + const char *path, + guint32 mode, + GError **error) +{ + if (!self || ostree_sepolicy_get_name (self) == NULL) + return TRUE; + + if (!ostree_sepolicy_setfscreatecon (self, path, mode, error)) + return FALSE; + + con->initialized = TRUE; + return TRUE; +} + +void +_ostree_sepolicy_fscreatecon_clear (OstreeSepolicyFsCreatecon *con) +{ + if (!con->initialized) + return; + ostree_sepolicy_fscreatecon_cleanup (NULL); +} + +/* + * Given @xattrs, filter out `security.selinux`, and return + * a new GVariant without it. Supports @xattrs as %NULL to + * mean "no xattrs", and also returns %NULL if no xattrs + * would result (rather than a zero-length array). + */ +GVariant * +_ostree_filter_selinux_xattr (GVariant *xattrs) +{ + if (!xattrs) + return NULL; + + gboolean have_xattrs = FALSE; + GVariantBuilder builder; + guint n = g_variant_n_children (xattrs); + for (guint i = 0; i < n; i++) + { + const char *name = NULL; + g_autoptr(GVariant) value = NULL; + + g_variant_get_child (xattrs, i, "(^&ay@ay)", + &name, &value); + + if (strcmp (name, "security.selinux") == 0) + continue; + /* Initialize builder lazily */ + if (!have_xattrs) + { + have_xattrs = TRUE; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)")); + } + g_variant_builder_add (&builder, "(@ay@ay)", + g_variant_new_bytestring (name), + value); + } + /* Canonicalize zero length to NULL for efficiency */ + if (!have_xattrs) + return NULL; + return g_variant_ref_sink (g_variant_builder_end (&builder)); +} diff --git a/src/libostree/ostree-sepolicy.h b/src/libostree/ostree-sepolicy.h new file mode 100644 index 0000000..7e90527 --- /dev/null +++ b/src/libostree/ostree-sepolicy.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_SEPOLICY ostree_sepolicy_get_type() +#define OSTREE_SEPOLICY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_SEPOLICY, OstreeSePolicy)) +#define OSTREE_IS_SEPOLICY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_SEPOLICY)) + +_OSTREE_PUBLIC +GType ostree_sepolicy_get_type (void); + +_OSTREE_PUBLIC +OstreeSePolicy* ostree_sepolicy_new (GFile *path, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeSePolicy* ostree_sepolicy_new_at (int rootfs_dfd, + GCancellable *cancellable, + GError **error); + + +_OSTREE_PUBLIC +GFile * ostree_sepolicy_get_path (OstreeSePolicy *self); + +_OSTREE_PUBLIC +const char *ostree_sepolicy_get_name (OstreeSePolicy *self); + +_OSTREE_PUBLIC +const char *ostree_sepolicy_get_csum (OstreeSePolicy *self); + +_OSTREE_PUBLIC +gboolean ostree_sepolicy_get_label (OstreeSePolicy *self, + const char *relpath, + guint32 unix_mode, + char **out_label, + GCancellable *cancellable, + GError **error); + +typedef enum { + OSTREE_SEPOLICY_RESTORECON_FLAGS_NONE, + OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL = (1 << 0), + OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING = (1 << 1) +} OstreeSePolicyRestoreconFlags; + +_OSTREE_PUBLIC +gboolean ostree_sepolicy_restorecon (OstreeSePolicy *self, + const char *path, + GFileInfo *info, + GFile *target, + OstreeSePolicyRestoreconFlags flags, + char **out_new_label, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sepolicy_setfscreatecon (OstreeSePolicy *self, + const char *path, + guint32 mode, + GError **error); + +_OSTREE_PUBLIC +void ostree_sepolicy_fscreatecon_cleanup (void **unused); + +#define ostree_cleanup_sepolicy_fscreatecon __attribute__ ((cleanup(ostree_sepolicy_fscreatecon_cleanup))) + +G_END_DECLS diff --git a/src/libostree/ostree-sign-dummy.c b/src/libostree/ostree-sign-dummy.c new file mode 100644 index 0000000..56f10d6 --- /dev/null +++ b/src/libostree/ostree-sign-dummy.c @@ -0,0 +1,196 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include +#include "ostree-sign-dummy.h" +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "OSTreeSign" + +#define OSTREE_SIGN_DUMMY_NAME "dummy" + +#define OSTREE_SIGN_METADATA_DUMMY_KEY "ostree.sign.dummy" +#define OSTREE_SIGN_METADATA_DUMMY_TYPE "aay" + +struct _OstreeSignDummy +{ + GObject parent; + gchar *sk_ascii; + gchar *pk_ascii; +}; + +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSignDummy, g_object_unref) +#endif + +static void +ostree_sign_dummy_iface_init (OstreeSignInterface *self); + +G_DEFINE_TYPE_WITH_CODE (OstreeSignDummy, _ostree_sign_dummy, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_SIGN, ostree_sign_dummy_iface_init)); + +static gboolean +check_dummy_sign_enabled (GError **error) +{ + if (g_strcmp0 (g_getenv ("OSTREE_DUMMY_SIGN_ENABLED"), "1") != 0) + return glnx_throw (error, "dummy signature type is only for ostree testing"); + return TRUE; +} + +static void +ostree_sign_dummy_iface_init (OstreeSignInterface *self) +{ + + self->get_name = ostree_sign_dummy_get_name; + self->data = ostree_sign_dummy_data; + self->data_verify = ostree_sign_dummy_data_verify; + self->metadata_key = ostree_sign_dummy_metadata_key; + self->metadata_format = ostree_sign_dummy_metadata_format; + self->set_sk = ostree_sign_dummy_set_sk; + self->set_pk = ostree_sign_dummy_set_pk; + /* Implementation for dummy engine just load the single public key */ + self->add_pk = ostree_sign_dummy_set_pk; +} + +static void +_ostree_sign_dummy_class_init (OstreeSignDummyClass *self) +{ +} + +static void +_ostree_sign_dummy_init (OstreeSignDummy *self) +{ + + self->sk_ascii = NULL; + self->pk_ascii = NULL; +} + +gboolean ostree_sign_dummy_set_sk (OstreeSign *self, GVariant *key, GError **error) +{ + if (!check_dummy_sign_enabled (error)) + return FALSE; + + OstreeSignDummy *sign = _ostree_sign_dummy_get_instance_private(OSTREE_SIGN_DUMMY(self)); + + g_free(sign->sk_ascii); + + sign->sk_ascii = g_variant_dup_string (key, 0); + + return TRUE; +} + +gboolean ostree_sign_dummy_set_pk (OstreeSign *self, GVariant *key, GError **error) +{ + OstreeSignDummy *sign = _ostree_sign_dummy_get_instance_private(OSTREE_SIGN_DUMMY(self)); + + g_free(sign->pk_ascii); + + sign->pk_ascii = g_variant_dup_string (key, 0); + + return TRUE; +} + +gboolean ostree_sign_dummy_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error) +{ + if (!check_dummy_sign_enabled (error)) + return FALSE; + + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + OstreeSignDummy *sign = _ostree_sign_dummy_get_instance_private(OSTREE_SIGN_DUMMY(self)); + + *signature = g_bytes_new (sign->sk_ascii, strlen(sign->sk_ascii)); + + return TRUE; +} + +const gchar * ostree_sign_dummy_get_name (OstreeSign *self) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + return OSTREE_SIGN_DUMMY_NAME; +} + +const gchar * ostree_sign_dummy_metadata_key (OstreeSign *self) +{ + + return OSTREE_SIGN_METADATA_DUMMY_KEY; +} + +const gchar * ostree_sign_dummy_metadata_format (OstreeSign *self) +{ + + return OSTREE_SIGN_METADATA_DUMMY_TYPE; +} + +gboolean ostree_sign_dummy_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error) +{ + if (!check_dummy_sign_enabled (error)) + return FALSE; + + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + OstreeSignDummy *sign = _ostree_sign_dummy_get_instance_private(OSTREE_SIGN_DUMMY(self)); + + if (signatures == NULL) + return glnx_throw (error, "signature: dummy: commit have no signatures of my type"); + + if (!g_variant_is_of_type (signatures, (GVariantType *) OSTREE_SIGN_METADATA_DUMMY_TYPE)) + return glnx_throw (error, "signature: dummy: wrong type passed for verification"); + + for (gsize i = 0; i < g_variant_n_children(signatures); i++) + { + g_autoptr (GVariant) child = g_variant_get_child_value (signatures, i); + g_autoptr (GBytes) signature = g_variant_get_data_as_bytes(child); + + gsize sign_size = 0; + g_bytes_get_data (signature, &sign_size); + g_autofree gchar *sign_ascii = g_strndup(g_bytes_get_data (signature, NULL), sign_size); + g_debug("Read signature %d: %s", (gint)i, sign_ascii); + g_debug("Stored signature %d: %s", (gint)i, sign->pk_ascii); + + if (!g_strcmp0(sign_ascii, sign->pk_ascii)) + { + if (out_success_message) + *out_success_message = g_strdup ("dummy: Signature verified"); + return TRUE; + } + else + return glnx_throw (error, "signature: dummy: incorrect signature %" G_GSIZE_FORMAT, i); + } + + return glnx_throw (error, "signature: dummy: no signatures"); +} diff --git a/src/libostree/ostree-sign-dummy.h b/src/libostree/ostree-sign-dummy.h new file mode 100644 index 0000000..bf5d63a --- /dev/null +++ b/src/libostree/ostree-sign-dummy.h @@ -0,0 +1,77 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Denis Pynkin (d4s) + */ + +#pragma once + +#include "ostree-sign.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_SIGN_DUMMY (_ostree_sign_dummy_get_type ()) + +GType _ostree_sign_dummy_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeSignDummy OstreeSignDummy; +typedef struct { GObjectClass parent_class; } OstreeSignDummyClass; + +static inline OstreeSignDummy *OSTREE_SIGN_DUMMY (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, _ostree_sign_dummy_get_type (), OstreeSignDummy); } +static inline gboolean OSTREE_IS_SIGN_DUMMY (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, _ostree_sign_dummy_get_type ()); } + +G_GNUC_END_IGNORE_DEPRECATIONS + +/* Have to use glib-2.44 for this +_OSTREE_PUBLIC +G_DECLARE_FINAL_TYPE (OstreeSignDummy, + ostree_sign_dummy, + OSTREE, + SIGN_DUMMY, + GObject) +*/ + +const gchar * ostree_sign_dummy_get_name (OstreeSign *self); + +gboolean ostree_sign_dummy_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error); + +gboolean ostree_sign_dummy_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **success_message, + GError **error); + +const gchar * ostree_sign_dummy_metadata_key (OstreeSign *self); +const gchar * ostree_sign_dummy_metadata_format (OstreeSign *self); + +gboolean ostree_sign_dummy_set_sk (OstreeSign *self, GVariant *key, GError **error); +gboolean ostree_sign_dummy_set_pk (OstreeSign *self, GVariant *key, GError **error); +gboolean ostree_sign_dummy_add_pk (OstreeSign *self, GVariant *key, GError **error); + +G_END_DECLS + diff --git a/src/libostree/ostree-sign-ed25519.c b/src/libostree/ostree-sign-ed25519.c new file mode 100644 index 0000000..d728afd --- /dev/null +++ b/src/libostree/ostree-sign-ed25519.c @@ -0,0 +1,672 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Denis Pynkin (d4s) + */ + +#include "config.h" + +#include +#include "ostree-sign-ed25519.h" +#ifdef HAVE_LIBSODIUM +#include +#endif + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "OSTreeSign" + +#define OSTREE_SIGN_ED25519_NAME "ed25519" + +#define OSTREE_SIGN_METADATA_ED25519_KEY "ostree.sign.ed25519" +#define OSTREE_SIGN_METADATA_ED25519_TYPE "aay" + +typedef enum +{ + ED25519_OK, + ED25519_NOT_SUPPORTED, + ED25519_FAILED_INITIALIZATION +} ed25519_state; + +struct _OstreeSignEd25519 +{ + GObject parent; + ed25519_state state; + guchar *secret_key; + GList *public_keys; + GList *revoked_keys; +}; + +#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSignEd25519, g_object_unref) +#endif + +static void +ostree_sign_ed25519_iface_init (OstreeSignInterface *self); + +G_DEFINE_TYPE_WITH_CODE (OstreeSignEd25519, _ostree_sign_ed25519, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_SIGN, ostree_sign_ed25519_iface_init)); + +static void +ostree_sign_ed25519_iface_init (OstreeSignInterface *self) +{ + + self->data = ostree_sign_ed25519_data; + self->data_verify = ostree_sign_ed25519_data_verify; + self->get_name = ostree_sign_ed25519_get_name; + self->metadata_key = ostree_sign_ed25519_metadata_key; + self->metadata_format = ostree_sign_ed25519_metadata_format; + self->clear_keys = ostree_sign_ed25519_clear_keys; + self->set_sk = ostree_sign_ed25519_set_sk; + self->set_pk = ostree_sign_ed25519_set_pk; + self->add_pk = ostree_sign_ed25519_add_pk; + self->load_pk = ostree_sign_ed25519_load_pk; +} + +static void +_ostree_sign_ed25519_class_init (OstreeSignEd25519Class *self) +{ +} + +static void +_ostree_sign_ed25519_init (OstreeSignEd25519 *self) +{ + + self->state = ED25519_OK; + self->secret_key = NULL; + self->public_keys = NULL; + self->revoked_keys = NULL; + +#ifdef HAVE_LIBSODIUM + if (sodium_init() < 0) + self->state = ED25519_FAILED_INITIALIZATION; +#else + self->state = ED25519_NOT_SUPPORTED; +#endif /* HAVE_LIBSODIUM */ +} + +static gboolean +_ostree_sign_ed25519_is_initialized (OstreeSignEd25519 *self, GError **error) +{ + switch (self->state) + { + case ED25519_OK: + break; + case ED25519_NOT_SUPPORTED: + return glnx_throw(error, "ed25519: engine is not supported"); + case ED25519_FAILED_INITIALIZATION: + return glnx_throw(error, "ed25519: libsodium library isn't initialized properly"); + } + + return TRUE; +} + +gboolean ostree_sign_ed25519_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error) +{ + + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + +#ifdef HAVE_LIBSODIUM + guchar *sig = NULL; +#endif + + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + + if (sign->secret_key == NULL) + return glnx_throw (error, "Not able to sign: secret key is not set"); + +#ifdef HAVE_LIBSODIUM + unsigned long long sig_size = 0; + + sig = g_malloc0(crypto_sign_BYTES); + + if (crypto_sign_detached (sig, + &sig_size, + g_bytes_get_data (data, NULL), + g_bytes_get_size (data), + sign->secret_key)) + { + return glnx_throw (error, "Not able to sign: fail to sign the object"); + } + + *signature = g_bytes_new_take (sig, sig_size); + return TRUE; +#endif /* HAVE_LIBSODIUM */ + return FALSE; +} + +#ifdef HAVE_LIBSODIUM +static gint +_compare_ed25519_keys(gconstpointer a, gconstpointer b) { + return memcmp (a, b, crypto_sign_PUBLICKEYBYTES); +} +#endif + +gboolean ostree_sign_ed25519_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + + if (signatures == NULL) + return glnx_throw (error, "ed25519: commit have no signatures of my type"); + + if (!g_variant_is_of_type (signatures, (GVariantType *) OSTREE_SIGN_METADATA_ED25519_TYPE)) + return glnx_throw (error, "ed25519: wrong type passed for verification"); + +#ifdef HAVE_LIBSODIUM + /* If no keys pre-loaded then, + * try to load public keys from storage(s) */ + if (sign->public_keys == NULL) + { + g_autoptr (GVariantBuilder) builder = NULL; + g_autoptr (GVariant) options = NULL; + + builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + options = g_variant_builder_end (builder); + + if (!ostree_sign_ed25519_load_pk (self, options, error)) + return FALSE; + } + + g_debug ("verify: data hash = 0x%x", g_bytes_hash(data)); + + g_autoptr(GString) invalid_signatures = NULL; + guint n_invalid_signatures = 0; + + for (gsize i = 0; i < g_variant_n_children(signatures); i++) + { + g_autoptr (GVariant) child = g_variant_get_child_value (signatures, i); + g_autoptr (GBytes) signature = g_variant_get_data_as_bytes(child); + + g_autofree char * hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES*2 + 1); + + g_debug("Read signature %d: %s", (gint)i, g_variant_print(child, TRUE)); + + for (GList *public_key = sign->public_keys; + public_key != NULL; + public_key = public_key->next) + { + + /* TODO: use non-list for tons of revoked keys? */ + if (g_list_find_custom (sign->revoked_keys, public_key->data, _compare_ed25519_keys) != NULL) + { + g_debug("Skip revoked key '%s'", + sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, public_key->data, crypto_sign_PUBLICKEYBYTES)); + continue; + } + + if (crypto_sign_verify_detached ((guchar *) g_variant_get_data (child), + g_bytes_get_data (data, NULL), + g_bytes_get_size (data), + public_key->data) != 0) + { + /* Incorrect signature! */ + if (invalid_signatures == NULL) + invalid_signatures = g_string_new (""); + else + g_string_append (invalid_signatures, "; "); + n_invalid_signatures++; + g_string_append_printf (invalid_signatures, "key '%s'", + sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, public_key->data, crypto_sign_PUBLICKEYBYTES)); + } + else + { + if (out_success_message) + { + *out_success_message = + g_strdup_printf ("ed25519: Signature verified successfully with key '%s'", + sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, public_key->data, crypto_sign_PUBLICKEYBYTES)); + } + return TRUE; + } + } + } + + if (invalid_signatures) + { + g_assert_cmpuint (n_invalid_signatures, >, 0); + /* The test suite has a key ring with 100 keys. This seems insane, let's + * cap a reasonable error message at 3. + */ + if (n_invalid_signatures > 3) + return glnx_throw (error, "ed25519: Signature couldn't be verified; tried %u keys", n_invalid_signatures); + return glnx_throw (error, "ed25519: Signature couldn't be verified with: %s", invalid_signatures->str); + } + return glnx_throw (error, "ed25519: no signatures found"); +#endif /* HAVE_LIBSODIUM */ + + return FALSE; +} + +const gchar * ostree_sign_ed25519_get_name (OstreeSign *self) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + return OSTREE_SIGN_ED25519_NAME; +} + +const gchar * ostree_sign_ed25519_metadata_key (OstreeSign *self) +{ + + return OSTREE_SIGN_METADATA_ED25519_KEY; +} + +const gchar * ostree_sign_ed25519_metadata_format (OstreeSign *self) +{ + + return OSTREE_SIGN_METADATA_ED25519_TYPE; +} + +gboolean ostree_sign_ed25519_clear_keys (OstreeSign *self, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + +#ifdef HAVE_LIBSODIUM + /* Clear secret key */ + if (sign->secret_key != NULL) + { + memset (sign->secret_key, 0, crypto_sign_SECRETKEYBYTES); + g_free (sign->secret_key); + sign->secret_key = NULL; + } + + /* Clear already loaded trusted keys */ + if (sign->public_keys != NULL) + { + g_list_free_full (sign->public_keys, g_free); + sign->public_keys = NULL; + } + + /* Clear already loaded revoked keys */ + if (sign->revoked_keys != NULL) + { + g_list_free_full (sign->revoked_keys, g_free); + sign->revoked_keys = NULL; + } + + return TRUE; +#endif /* HAVE_LIBSODIUM */ + + return FALSE; +} + +/* Support 2 representations: + * base64 ascii -- secret key is passed as string + * raw key -- key is passed as bytes array + * */ +gboolean ostree_sign_ed25519_set_sk (OstreeSign *self, + GVariant *secret_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + + if (!ostree_sign_ed25519_clear_keys (self, error)) + return FALSE; + +#ifdef HAVE_LIBSODIUM + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + gsize n_elements = 0; + + if (g_variant_is_of_type (secret_key, G_VARIANT_TYPE_STRING)) + { + const gchar *sk_ascii = g_variant_get_string (secret_key, NULL); + sign->secret_key = g_base64_decode (sk_ascii, &n_elements); + } + else if (g_variant_is_of_type (secret_key, G_VARIANT_TYPE_BYTESTRING)) + { + sign->secret_key = (guchar *) g_variant_get_fixed_array (secret_key, &n_elements, sizeof(guchar)); + } + else + { + return glnx_throw (error, "Unknown ed25519 secret key type"); + } + + if (n_elements != crypto_sign_SECRETKEYBYTES) + return glnx_throw (error, "Incorrect ed25519 secret key"); + + return TRUE; +#endif /* HAVE_LIBSODIUM */ + + return FALSE; +} + +/* Support 2 representations: + * base64 ascii -- public key is passed as string + * raw key -- key is passed as bytes array + * */ +gboolean ostree_sign_ed25519_set_pk (OstreeSign *self, + GVariant *public_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + if (!ostree_sign_ed25519_clear_keys (self, error)) + return FALSE; + + return ostree_sign_ed25519_add_pk (self, public_key, error); +} + +/* Support 2 representations: + * base64 ascii -- public key is passed as string + * raw key -- key is passed as bytes array + * */ +gboolean ostree_sign_ed25519_add_pk (OstreeSign *self, + GVariant *public_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + +#ifdef HAVE_LIBSODIUM + gpointer key = NULL; + gsize n_elements = 0; + + if (g_variant_is_of_type (public_key, G_VARIANT_TYPE_STRING)) + { + const gchar *pk_ascii = g_variant_get_string (public_key, NULL); + key = g_base64_decode (pk_ascii, &n_elements); + } + else if (g_variant_is_of_type (public_key, G_VARIANT_TYPE_BYTESTRING)) + { + key = (gpointer) g_variant_get_fixed_array (public_key, &n_elements, sizeof(guchar)); + } + else + { + return glnx_throw (error, "Unknown ed25519 public key type"); + } + + if (n_elements != crypto_sign_PUBLICKEYBYTES) + return glnx_throw (error, "Incorrect ed25519 public key"); + + g_autofree char *hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES*2 + 1); + g_debug ("Read ed25519 public key = %s", sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, key, n_elements)); + + if (g_list_find_custom (sign->public_keys, key, _compare_ed25519_keys) == NULL) + { + gpointer newkey = g_memdup (key, n_elements); + sign->public_keys = g_list_prepend (sign->public_keys, newkey); + } + +#endif /* HAVE_LIBSODIUM */ + return TRUE; +} + +#ifdef HAVE_LIBSODIUM +/* Add revoked public key */ +static gboolean +_ed25519_add_revoked (OstreeSign *self, + GVariant *revoked_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + if (!g_variant_is_of_type (revoked_key, G_VARIANT_TYPE_STRING)) + return glnx_throw (error, "Unknown ed25519 revoked key type"); + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + + const gchar *rk_ascii = g_variant_get_string (revoked_key, NULL); + gsize n_elements = 0; + gpointer key = g_base64_decode (rk_ascii, &n_elements); + + if (n_elements != crypto_sign_PUBLICKEYBYTES) + { + return glnx_throw (error, "Incorrect ed25519 revoked key"); + } + + g_autofree char * hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES*2 + 1); + g_debug ("Read ed25519 revoked key = %s", sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, key, n_elements)); + + if (g_list_find_custom (sign->revoked_keys, key, _compare_ed25519_keys) == NULL) + { + gpointer newkey = g_memdup (key, n_elements); + sign->revoked_keys = g_list_prepend (sign->revoked_keys, newkey); + } + + return TRUE; +} +#endif /* HAVE_LIBSODIUM */ + + +static gboolean +_load_pk_from_stream (OstreeSign *self, + GDataInputStream *key_data_in, + gboolean trusted, + GError **error) +{ + g_return_val_if_fail (key_data_in, FALSE); +#ifdef HAVE_LIBSODIUM + gboolean ret = FALSE; + + /* Use simple file format with just a list of base64 public keys per line */ + while (TRUE) + { + gsize len = 0; + g_autofree char *line = g_data_input_stream_read_line (key_data_in, &len, NULL, error); + g_autoptr (GVariant) pk = NULL; + gboolean added = FALSE; + + if (*error != NULL) + return FALSE; + + if (line == NULL) + return ret; + + /* Read the key itself */ + /* base64 encoded key */ + pk = g_variant_new_string (line); + + if (trusted) + added = ostree_sign_ed25519_add_pk (self, pk, error); + else + added = _ed25519_add_revoked (self, pk, error); + + g_debug ("%s %s key: %s", + added ? "Added" : "Invalid", + trusted ? "public" : "revoked", + line); + + /* Mark what we load at least one key */ + if (added) + ret = TRUE; + } +#endif /* HAVE_LIBSODIUM */ + return FALSE; +} + +static gboolean +_load_pk_from_file (OstreeSign *self, + const gchar *filename, + gboolean trusted, + GError **error) +{ + g_debug ("Processing file '%s'", filename); + + g_autoptr (GFile) keyfile = NULL; + g_autoptr (GFileInputStream) key_stream_in = NULL; + g_autoptr (GDataInputStream) key_data_in = NULL; + + if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + { + g_debug ("Can't open file '%s' with public keys", filename); + return glnx_throw (error, "File object '%s' is not a regular file", filename); + } + + keyfile = g_file_new_for_path (filename); + key_stream_in = g_file_read (keyfile, NULL, error); + if (key_stream_in == NULL) + return FALSE; + + key_data_in = g_data_input_stream_new (G_INPUT_STREAM(key_stream_in)); + g_assert (key_data_in != NULL); + + if (!_load_pk_from_stream (self, key_data_in, trusted, error)) + { + if (error == NULL || *error == NULL) + return glnx_throw (error, + "signature: ed25519: no valid keys in file '%s'", + filename); + else + return FALSE; + } + + return TRUE; +} + +static gboolean +_ed25519_load_pk (OstreeSign *self, + GVariant *options, + gboolean trusted, + GError **error) +{ + + gboolean ret = FALSE; + const gchar *custom_dir = NULL; + + g_autoptr (GPtrArray) base_dirs = g_ptr_array_new_with_free_func (g_free); + g_autoptr (GPtrArray) ed25519_files = g_ptr_array_new_with_free_func (g_free); + + if (g_variant_lookup (options, "basedir", "&s", &custom_dir)) + { + /* Add custom directory */ + g_ptr_array_add (base_dirs, g_strdup (custom_dir)); + } + else + { + /* Default paths where to find files with public keys */ + g_ptr_array_add (base_dirs, g_strdup ("/etc/ostree")); + g_ptr_array_add (base_dirs, g_strdup (DATADIR "/ostree")); + } + + /* Scan all well-known directories and construct the list with file names to scan keys */ + for (gint i=0; i < base_dirs->len; i++) + { + gchar *base_name = NULL; + g_autofree gchar *base_dir = NULL; + g_autoptr (GDir) dir = NULL; + + base_name = g_build_filename ((gchar *)g_ptr_array_index (base_dirs, i), + trusted ? "trusted.ed25519" : "revoked.ed25519", + NULL); + + g_debug ("Check ed25519 keys from file: %s", base_name); + g_ptr_array_add (ed25519_files, base_name); + + base_dir = g_strconcat (base_name, ".d", NULL); + dir = g_dir_open (base_dir, 0, error); + if (dir == NULL) + { + g_clear_error (error); + continue; + } + const gchar *entry = NULL; + while ((entry = g_dir_read_name (dir)) != NULL) + { + gchar *filename = g_build_filename (base_dir, entry, NULL); + g_debug ("Check ed25519 keys from file: %s", filename); + g_ptr_array_add (ed25519_files, filename); + } + } + + /* Scan all well-known files */ + for (gint i=0; i < ed25519_files->len; i++) + { + if (!_load_pk_from_file (self, (gchar *)g_ptr_array_index (ed25519_files, i), trusted, error)) + { + g_debug ("Problem with loading ed25519 %s keys from `%s`", + trusted ? "public" : "revoked", + (gchar *)g_ptr_array_index (ed25519_files, i)); + g_clear_error(error); + } + else + ret = TRUE; + } + + if (!ret && (error == NULL || *error == NULL)) + return glnx_throw (error, "signature: ed25519: no keys loaded"); + + return ret; +} + +/* + * options argument should be a{sv}: + * - filename -- single file to use to load keys from; + * - basedir -- directory containing subdirectories + * 'trusted.ed25519.d' and 'revoked.ed25519.d' with appropriate + * public keys. Used for testing and re-definition of system-wide + * directories if defaults are not suitable for any reason. + */ +gboolean +ostree_sign_ed25519_load_pk (OstreeSign *self, + GVariant *options, + GError **error) +{ + + const gchar *filename = NULL; + + OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self)); + if (!_ostree_sign_ed25519_is_initialized (sign, error)) + return FALSE; + + /* Read keys only from single file provided */ + if (g_variant_lookup (options, "filename", "&s", &filename)) + return _load_pk_from_file (self, filename, TRUE, error); + + /* Load public keys from well-known directories and files */ + if (!_ed25519_load_pk (self, options, TRUE, error)) + return FALSE; + + /* Load untrusted keys from well-known directories and files + * Ignore the failure from this function -- it is expected to have + * empty list of revoked keys. + * */ + if (!_ed25519_load_pk (self, options, FALSE, error)) + g_clear_error(error); + + return TRUE; +} diff --git a/src/libostree/ostree-sign-ed25519.h b/src/libostree/ostree-sign-ed25519.h new file mode 100644 index 0000000..72152ea --- /dev/null +++ b/src/libostree/ostree-sign-ed25519.h @@ -0,0 +1,91 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Denis Pynkin (d4s) + */ + +#pragma once + +#include "ostree-sign.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_SIGN_ED25519 (_ostree_sign_ed25519_get_type ()) + +GType _ostree_sign_ed25519_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeSignEd25519 OstreeSignEd25519; +typedef struct { GObjectClass parent_class; } OstreeSignEd25519Class; + +static inline OstreeSignEd25519 *OSTREE_SIGN_ED25519 (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, _ostree_sign_ed25519_get_type (), OstreeSignEd25519); } +static inline gboolean OSTREE_IS_SIGN_ED25519 (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, _ostree_sign_ed25519_get_type ()); } + +G_GNUC_END_IGNORE_DEPRECATIONS + +/* Have to use glib-2.44 for this +_OSTREE_PUBLIC +G_DECLARE_FINAL_TYPE (OstreeSignEd25519, + ostree_sign_ed25519, + OSTREE, + SIGN_ED25519, + GObject) +*/ + +gboolean ostree_sign_ed25519_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error); + +gboolean ostree_sign_ed25519_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error); + +const gchar * ostree_sign_ed25519_get_name (OstreeSign *self); +const gchar * ostree_sign_ed25519_metadata_key (OstreeSign *self); +const gchar * ostree_sign_ed25519_metadata_format (OstreeSign *self); + +gboolean ostree_sign_ed25519_clear_keys (OstreeSign *self, + GError **error); + +gboolean ostree_sign_ed25519_set_sk (OstreeSign *self, + GVariant *secret_key, + GError **error); + +gboolean ostree_sign_ed25519_set_pk (OstreeSign *self, + GVariant *public_key, + GError **error); + +gboolean ostree_sign_ed25519_add_pk (OstreeSign *self, + GVariant *public_key, + GError **error); + +gboolean ostree_sign_ed25519_load_pk (OstreeSign *self, + GVariant *options, + GError **error); + +G_END_DECLS + diff --git a/src/libostree/ostree-sign.c b/src/libostree/ostree-sign.c new file mode 100644 index 0000000..bcb5d0a --- /dev/null +++ b/src/libostree/ostree-sign.c @@ -0,0 +1,668 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/** + * SECTION:ostree-sign + * @title: Signature management + * @short_description: Sign and verify commits + * + * An #OstreeSign interface allows to select and use any available engine + * for signing or verifying the commit object or summary file. + */ + +#include "config.h" + +#include +#include +#include +#include "libglnx.h" +#include "otutil.h" + +#include "ostree-autocleanups.h" +#include "ostree-core.h" +#include "ostree-sign.h" +#include "ostree-sign-dummy.h" +#ifdef HAVE_LIBSODIUM +#include "ostree-sign-ed25519.h" +#endif + +#include "ostree-autocleanups.h" +#include "ostree-repo-private.h" + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "OSTreeSign" + +typedef struct +{ + gchar *name; + GType type; +} _sign_type; + +_sign_type sign_types[] = +{ +#if defined(HAVE_LIBSODIUM) + {OSTREE_SIGN_NAME_ED25519, 0}, +#endif + {"dummy", 0} +}; + +enum +{ +#if defined(HAVE_LIBSODIUM) + SIGN_ED25519, +#endif + SIGN_DUMMY +}; + +G_DEFINE_INTERFACE (OstreeSign, ostree_sign, G_TYPE_OBJECT) + +static void +ostree_sign_default_init (OstreeSignInterface *iface) +{ + g_debug ("OstreeSign initialization"); +} + +/** + * ostree_sign_metadata_key: + * @self: an #OstreeSign object + * + * Return the pointer to the name of the key used in (detached) metadata for + * current signing engine. + * + * Returns: (transfer none): pointer to the metadata key name, + * @NULL in case of error (unlikely). + * + * Since: 2020.2 + */ +const gchar * +ostree_sign_metadata_key (OstreeSign *self) +{ + + g_return_val_if_fail (OSTREE_SIGN_GET_IFACE (self)->metadata_key != NULL, NULL); + return OSTREE_SIGN_GET_IFACE (self)->metadata_key (self); +} + +/** + * ostree_sign_metadata_format: + * @self: an #OstreeSign object + * + * Return the pointer to the string with format used in (detached) metadata for + * current signing engine. + * + * Returns: (transfer none): pointer to the metadata format, + * @NULL in case of error (unlikely). + * + * Since: 2020.2 + */ +const gchar * +ostree_sign_metadata_format (OstreeSign *self) +{ + + g_return_val_if_fail (OSTREE_SIGN_GET_IFACE (self)->metadata_format != NULL, NULL); + return OSTREE_SIGN_GET_IFACE (self)->metadata_format (self); +} + +/** + * ostree_sign_clear_keys: + * @self: an #OstreeSign object + * @error: a #GError + * + * Clear all previously preloaded secret and public keys. + * + * Returns: @TRUE in case if no errors, @FALSE in case of error + * + * Since: 2020.2 + */ +gboolean +ostree_sign_clear_keys (OstreeSign *self, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->clear_keys == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->clear_keys (self, error); +} + +/** + * ostree_sign_set_sk: + * @self: an #OstreeSign object + * @secret_key: secret key to be added + * @error: a #GError + * + * Set the secret key to be used for signing data, commits and summary. + * + * The @secret_key argument depends of the particular engine implementation. + * + * Returns: @TRUE in case if the key could be set successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_set_sk (OstreeSign *self, + GVariant *secret_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->set_sk == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->set_sk (self, secret_key, error); +} + +/** + * ostree_sign_set_pk: + * @self: an #OstreeSign object + * @public_key: single public key to be added + * @error: a #GError + * + * Set the public key for verification. It is expected what all + * previously pre-loaded public keys will be dropped. + * + * The @public_key argument depends of the particular engine implementation. + * + * Returns: @TRUE in case if the key could be set successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_set_pk (OstreeSign *self, + GVariant *public_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->set_pk == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->set_pk (self, public_key, error); +} + +/** + * ostree_sign_add_pk: + * @self: an #OstreeSign object + * @public_key: single public key to be added + * @error: a #GError + * + * Add the public key for verification. Could be called multiple times for + * adding all needed keys to be used for verification. + * + * The @public_key argument depends of the particular engine implementation. + * + * Returns: @TRUE in case if the key could be added successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_add_pk (OstreeSign *self, + GVariant *public_key, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->add_pk == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->add_pk (self, public_key, error); +} + +/** + * ostree_sign_load_pk: + * @self: an #OstreeSign object + * @options: any options + * @error: a #GError + * + * Load public keys for verification from anywhere. + * It is expected that all keys would be added to already pre-loaded keys. + * + * The @options argument depends of the particular engine implementation. + * + * For example, @ed25515 engine could use following string-formatted options: + * - @filename -- single file to use to load keys from + * - @basedir -- directory containing subdirectories + * 'trusted.ed25519.d' and 'revoked.ed25519.d' with appropriate + * public keys. Used for testing and re-definition of system-wide + * directories if defaults are not suitable for any reason. + * + * Returns: @TRUE in case if at least one key could be load successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +/* + * No need to have similar function for secret keys load -- it is expected + * what the signing software will load the secret key in it's own way. + */ +gboolean +ostree_sign_load_pk (OstreeSign *self, + GVariant *options, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->load_pk == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->load_pk (self, options, error); +} + +/** + * ostree_sign_data: + * @self: an #OstreeSign object + * @data: the raw data to be signed with pre-loaded secret key + * @signature: in case of success will contain signature + * @cancellable: A #GCancellable + * @error: a #GError + * + * Sign the given @data with pre-loaded secret key. + * + * Depending of the signing engine used you will need to load + * the secret key with #ostree_sign_set_sk. + * + * Returns: @TRUE if @data has been signed successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error) +{ + + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->data == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->data (self, data, signature, cancellable, error); +} + +/** + * ostree_sign_data_verify: + * @self: an #OstreeSign object + * @data: the raw data to check + * @signatures: the signatures to be checked + * @error: a #GError + * + * Verify given data against signatures with pre-loaded public keys. + * + * Depending of the signing engine used you will need to load + * the public key(s) with #ostree_sign_set_pk, #ostree_sign_add_pk + * or #ostree_sign_load_pk. + * + * Returns: @TRUE if @data has been signed at least with any single valid key, + * @FALSE in case of error or no valid keys are available (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + if (OSTREE_SIGN_GET_IFACE (self)->data_verify == NULL) + return glnx_throw (error, "not implemented"); + + return OSTREE_SIGN_GET_IFACE (self)->data_verify(self, data, signatures, out_success_message, error); +} + +/* + * Adopted version of _ostree_detached_metadata_append_gpg_sig () + */ +static GVariant * +_sign_detached_metadata_append (OstreeSign *self, + GVariant *existing_metadata, + GBytes *signature_bytes) +{ + g_return_val_if_fail (signature_bytes != NULL, FALSE); + + GVariantDict metadata_dict; + g_autoptr(GVariant) signature_data = NULL; + g_autoptr(GVariantBuilder) signature_builder = NULL; + + g_variant_dict_init (&metadata_dict, existing_metadata); + + const gchar *signature_key = ostree_sign_metadata_key(self); + GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format(self); + + signature_data = g_variant_dict_lookup_value (&metadata_dict, + signature_key, + (GVariantType*)signature_format); + + /* signature_data may be NULL */ + signature_builder = ot_util_variant_builder_from_variant (signature_data, signature_format); + + g_variant_builder_add (signature_builder, "@ay", ot_gvariant_new_ay_bytes (signature_bytes)); + + g_variant_dict_insert_value (&metadata_dict, + signature_key, + g_variant_builder_end (signature_builder)); + + return g_variant_dict_end (&metadata_dict); +} + +/** + * ostree_sign_commit_verify: + * @self: an #OstreeSign object + * @repo: an #OsreeRepo object + * @commit_checksum: SHA256 of given commit to verify + * @cancellable: A #GCancellable + * @error: a #GError + * + * Verify if commit is signed with known key. + * + * Depending of the signing engine used you will need to load + * the public key(s) for verification with #ostree_sign_set_pk, + * #ostree_sign_add_pk and/or #ostree_sign_load_pk. + * + * Returns: @TRUE if commit has been verified successfully, + * @FALSE in case of error or no valid keys are available (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_commit_verify (OstreeSign *self, + OstreeRepo *repo, + const gchar *commit_checksum, + char **out_success_message, + GCancellable *cancellable, + GError **error) + +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + + g_autoptr(GVariant) commit_variant = NULL; + /* Load the commit */ + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + commit_checksum, &commit_variant, + error)) + return glnx_prefix_error (error, "Failed to read commit"); + + /* Load the metadata */ + g_autoptr(GVariant) metadata = NULL; + if (!ostree_repo_read_commit_detached_metadata (repo, + commit_checksum, + &metadata, + cancellable, + error)) + return glnx_prefix_error (error, "Failed to read detached metadata"); + + g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit_variant); + + g_autoptr(GVariant) signatures = NULL; + + const gchar *signature_key = ostree_sign_metadata_key(self); + GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format(self); + + if (metadata) + signatures = g_variant_lookup_value (metadata, + signature_key, + signature_format); + + + return ostree_sign_data_verify (self, + signed_data, + signatures, + out_success_message, + error); +} + +/** + * ostree_sign_get_name: + * @self: an #OstreeSign object + * + * Return the pointer to the name of currently used/selected signing engine. + * + * Returns: (transfer none): pointer to the name + * @NULL in case of error (unlikely). + * + * Since: 2020.2 + */ +const gchar * +ostree_sign_get_name (OstreeSign *self) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), NULL); + g_return_val_if_fail (OSTREE_SIGN_GET_IFACE (self)->get_name != NULL, NULL); + + return OSTREE_SIGN_GET_IFACE (self)->get_name (self); +} + +/** + * ostree_sign_commit: + * @self: an #OstreeSign object + * @repo: an #OsreeRepo object + * @commit_checksum: SHA256 of given commit to sign + * @cancellable: A #GCancellable + * @error: a #GError + * + * Add a signature to a commit. + * + * Depending of the signing engine used you will need to load + * the secret key with #ostree_sign_set_sk. + * + * Returns: @TRUE if commit has been signed successfully, + * @FALSE in case of error (@error will contain the reason). + * + * Since: 2020.2 + */ +gboolean +ostree_sign_commit (OstreeSign *self, + OstreeRepo *repo, + const gchar *commit_checksum, + GCancellable *cancellable, + GError **error) +{ + + g_autoptr(GBytes) commit_data = NULL; + g_autoptr(GBytes) signature = NULL; + g_autoptr(GVariant) commit_variant = NULL; + g_autoptr(GVariant) old_metadata = NULL; + g_autoptr(GVariant) new_metadata = NULL; + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + commit_checksum, &commit_variant, error)) + return glnx_prefix_error (error, "Failed to read commit"); + + if (!ostree_repo_read_commit_detached_metadata (repo, + commit_checksum, + &old_metadata, + cancellable, + error)) + return glnx_prefix_error (error, "Failed to read detached metadata"); + + commit_data = g_variant_get_data_as_bytes (commit_variant); + + if (!ostree_sign_data (self, commit_data, &signature, + cancellable, error)) + return glnx_prefix_error (error, "Not able to sign the cobject"); + + new_metadata = + _sign_detached_metadata_append (self, old_metadata, signature); + + if (!ostree_repo_write_commit_detached_metadata (repo, + commit_checksum, + new_metadata, + cancellable, + error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sign_get_all: + * + * Return an array with newly allocated instances of all available + * signing engines; they will not be initialized. + * + * Returns: (transfer full) (element-type OstreeSign): an array of signing engines + * + * Since: 2020.2 + */ +GPtrArray * +ostree_sign_get_all (void) +{ + g_autoptr(GPtrArray) engines = g_ptr_array_new_with_free_func (g_object_unref); + for (guint i = 0; i < G_N_ELEMENTS(sign_types); i++) + { + OstreeSign *engine = ostree_sign_get_by_name (sign_types[i].name, NULL); + g_assert (engine); + g_ptr_array_add (engines, engine); + } + + return g_steal_pointer (&engines); +} + +/** + * ostree_sign_get_by_name: + * @name: the name of desired signature engine + * @error: return location for a #GError + * + * Create a new instance of a signing engine. + * + * Returns: (transfer full): New signing engine, or %NULL if the engine is not known + * + * Since: 2020.2 + */ +OstreeSign * +ostree_sign_get_by_name (const gchar *name, GError **error) +{ + + OstreeSign *sign = NULL; + + /* Get types if not initialized yet */ +#if defined(HAVE_LIBSODIUM) + if (sign_types[SIGN_ED25519].type == 0) + sign_types[SIGN_ED25519].type = OSTREE_TYPE_SIGN_ED25519; +#endif + if (sign_types[SIGN_DUMMY].type == 0) + sign_types[SIGN_DUMMY].type = OSTREE_TYPE_SIGN_DUMMY; + + for (gint i=0; i < G_N_ELEMENTS(sign_types); i++) + { + if (g_strcmp0 (name, sign_types[i].name) == 0) + { + g_debug ("Using '%s' signing engine", sign_types[i].name); + sign = g_object_new (sign_types[i].type, NULL); + break; + } + } + + if (sign == NULL) + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Requested signature type is not implemented"); + + return sign; +} + +/** + * ostree_sign_summary: + * @self: Self + * @repo: ostree repository + * @keys: keys -- GVariant containing keys as GVarints specific to signature type. + * @cancellable: A #GCancellable + * @error: a #GError + * + * Add a signature to a summary file. + * Based on ostree_repo_add_gpg_signature_summary implementation. + * + * Returns: @TRUE if summary file has been signed with all provided keys + */ +gboolean +ostree_sign_summary (OstreeSign *self, + OstreeRepo *repo, + GVariant *keys, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE); + g_return_val_if_fail (OSTREE_IS_REPO (repo), FALSE); + + g_autoptr(GVariant) normalized = NULL; + g_autoptr(GBytes) summary_data = NULL; + g_autoptr(GVariant) metadata = NULL; + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (repo->repo_dir_fd, "summary", TRUE, &fd, error)) + return FALSE; + summary_data = ot_fd_readall_or_mmap (fd, 0, error); + if (!summary_data) + return FALSE; + + /* Note that fd is reused below */ + glnx_close_fd (&fd); + + if (!ot_openat_ignore_enoent (repo->repo_dir_fd, "summary.sig", &fd, error)) + return FALSE; + + if (fd >= 0) + { + if (!ot_variant_read_fd (fd, 0, OSTREE_SUMMARY_SIG_GVARIANT_FORMAT, + FALSE, &metadata, error)) + return FALSE; + } + + if (g_variant_n_children(keys) == 0) + return glnx_throw (error, "No keys passed for signing summary"); + + GVariantIter *iter; + GVariant *key; + + g_variant_get (keys, "av", &iter); + while (g_variant_iter_loop (iter, "v", &key)) + { + g_autoptr (GBytes) signature = NULL; + + if (!ostree_sign_set_sk (self, key, error)) + return FALSE; + + if (!ostree_sign_data (self, + summary_data, + &signature, + cancellable, + error)) + return FALSE; + + g_autoptr(GVariant) old_metadata = g_steal_pointer (&metadata); + metadata = + _sign_detached_metadata_append (self, old_metadata, signature); + } + g_variant_iter_free (iter); + + normalized = g_variant_get_normal_form (metadata); + if (!_ostree_repo_file_replace_contents (repo, + repo->repo_dir_fd, + "summary.sig", + g_variant_get_data (normalized), + g_variant_get_size (normalized), + cancellable, error)) + return FALSE; + + return TRUE; +} diff --git a/src/libostree/ostree-sign.h b/src/libostree/ostree-sign.h new file mode 100644 index 0000000..0d06905 --- /dev/null +++ b/src/libostree/ostree-sign.h @@ -0,0 +1,171 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright © 2019 Collabora Ltd. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Denis Pynkin (d4s) + */ + +#pragma once + +#include +#include + +#include "ostree-ref.h" +#include "ostree-remote.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_SIGN (ostree_sign_get_type ()) + +_OSTREE_PUBLIC +GType ostree_sign_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeSign OstreeSign; +typedef struct _OstreeSignInterface OstreeSignInterface; + +static inline OstreeSign *OSTREE_SIGN (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_sign_get_type (), OstreeSign); } +static inline gboolean OSTREE_IS_SIGN (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_sign_get_type ()); } +static inline OstreeSignInterface *OSTREE_SIGN_GET_IFACE (gpointer ptr) { return G_TYPE_INSTANCE_GET_INTERFACE (ptr, ostree_sign_get_type (), OstreeSignInterface); } +G_GNUC_END_IGNORE_DEPRECATIONS + +/** + * OSTREE_SIGN_NAME_ED25519: + * The name of the default ed25519 signing type. + */ +#define OSTREE_SIGN_NAME_ED25519 "ed25519" + +/* Have to use glib-2.44 for this +_OSTREE_PUBLIC +G_DECLARE_INTERFACE (OstreeSign, ostree_sign, OSTREE, SIGN, GObject) +*/ + +struct _OstreeSignInterface +{ + GTypeInterface g_iface; + const gchar *(* get_name) (OstreeSign *self); + gboolean (* data) (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error); + gboolean (* data_verify) (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error); + const gchar *(* metadata_key) (OstreeSign *self); + const gchar *(* metadata_format) (OstreeSign *self); + gboolean (* clear_keys) (OstreeSign *self, + GError **error); + gboolean (* set_sk) (OstreeSign *self, + GVariant *secret_key, + GError **error); + gboolean (* set_pk) (OstreeSign *self, + GVariant *public_key, + GError **error); + gboolean (* add_pk) (OstreeSign *self, + GVariant *public_key, + GError **error); + gboolean (* load_pk) (OstreeSign *self, + GVariant *options, + GError **error); +}; + +_OSTREE_PUBLIC +const gchar * ostree_sign_get_name (OstreeSign *self); + +_OSTREE_PUBLIC +gboolean ostree_sign_data (OstreeSign *self, + GBytes *data, + GBytes **signature, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_data_verify (OstreeSign *self, + GBytes *data, + GVariant *signatures, + char **out_success_message, + GError **error); + +_OSTREE_PUBLIC +const gchar * ostree_sign_metadata_key (OstreeSign *self); + +_OSTREE_PUBLIC +const gchar * ostree_sign_metadata_format (OstreeSign *self); + +_OSTREE_PUBLIC +gboolean ostree_sign_commit (OstreeSign *self, + OstreeRepo *repo, + const gchar *commit_checksum, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_commit_verify (OstreeSign *self, + OstreeRepo *repo, + const gchar *commit_checksum, + char **out_success_message, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_clear_keys (OstreeSign *self, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_set_sk (OstreeSign *self, + GVariant *secret_key, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_set_pk (OstreeSign *self, + GVariant *public_key, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_add_pk (OstreeSign *self, + GVariant *public_key, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_load_pk (OstreeSign *self, + GVariant *options, + GError **error); + + +_OSTREE_PUBLIC +GPtrArray * ostree_sign_get_all(void); + +_OSTREE_PUBLIC +OstreeSign * ostree_sign_get_by_name (const gchar *name, GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sign_summary (OstreeSign *self, + OstreeRepo *repo, + GVariant *keys, + GCancellable *cancellable, + GError **error); +G_END_DECLS + diff --git a/src/libostree/ostree-soup-form.c b/src/libostree/ostree-soup-form.c new file mode 100644 index 0000000..dfaffb9 --- /dev/null +++ b/src/libostree/ostree-soup-form.c @@ -0,0 +1,140 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* soup-form.c : utility functions for HTML forms */ + +/* + * Copyright 2008 Red Hat, Inc. + */ + +/* This one is stripped down to only have soup_form_encode_hash() + * and soup_form_encode_valist() which are the only bits that soup-uri.c + * calls. + */ + +#include + +#include + +#include "ostree-soup-uri.h" + +/** + * SECTION:soup-form + * @short_description: HTML form handling + * @see_also: #SoupMultipart + * + * libsoup contains several help methods for processing HTML forms as + * defined by the + * HTML 4.01 specification. + **/ + +/** + * SOUP_FORM_MIME_TYPE_URLENCODED: + * + * A macro containing the value + * "application/x-www-form-urlencoded"; the default + * MIME type for POSTing HTML form data. + * + * Since: 2.26 + **/ + +/** + * SOUP_FORM_MIME_TYPE_MULTIPART: + * + * A macro containing the value + * "multipart/form-data"; the MIME type used for + * posting form data that contains files to be uploaded. + * + * Since: 2.26 + **/ + +#define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10) +#define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2])) + +static void +append_form_encoded (GString *str, const char *in) +{ + const unsigned char *s = (const unsigned char *)in; + + while (*s) { + if (*s == ' ') { + g_string_append_c (str, '+'); + s++; + } else if (!g_ascii_isalnum (*s) && (*s != '-') && (*s != '_') + && (*s != '.')) + g_string_append_printf (str, "%%%02X", (int)*s++); + else + g_string_append_c (str, *s++); + } +} + +static void +encode_pair (GString *str, const char *name, const char *value) +{ + g_return_if_fail (name != NULL); + g_return_if_fail (value != NULL); + + if (str->len) + g_string_append_c (str, '&'); + append_form_encoded (str, name); + g_string_append_c (str, '='); + append_form_encoded (str, value); +} + +/** + * soup_form_encode_hash: + * @form_data_set: (element-type utf8 utf8) (transfer none): a hash table containing + * name/value pairs (as strings) + * + * Encodes @form_data_set into a value of type + * "application/x-www-form-urlencoded", as defined in the HTML 4.01 + * spec. + * + * Note that the HTML spec states that "The control names/values are + * listed in the order they appear in the document." Since this method + * takes a hash table, it cannot enforce that; if you care about the + * ordering of the form fields, use soup_form_encode_datalist(). + * + * Return value: the encoded form + **/ +char * +soup_form_encode_hash (GHashTable *form_data_set) +{ + GString *str = g_string_new (NULL); + GHashTableIter iter; + gpointer name, value; + + g_hash_table_iter_init (&iter, form_data_set); + while (g_hash_table_iter_next (&iter, &name, &value)) + encode_pair (str, name, value); + return g_string_free (str, FALSE); +} + +/** + * soup_form_encode_valist: + * @first_field: name of the first form field + * @args: pointer to additional values, as in soup_form_encode() + * + * See soup_form_encode(). This is mostly an internal method, used by + * various other methods such as soup_uri_set_query_from_fields() and + * soup_form_request_new(). + * + * Return value: the encoded form + **/ +char * +soup_form_encode_valist (const char *first_field, va_list args) +{ + GString *str = g_string_new (NULL); + const char *name, *value; + + name = first_field; + value = va_arg (args, const char *); + while (name && value) { + encode_pair (str, name, value); + + name = va_arg (args, const char *); + if (name) + value = va_arg (args, const char *); + } + + return g_string_free (str, FALSE); +} diff --git a/src/libostree/ostree-soup-uri.c b/src/libostree/ostree-soup-uri.c new file mode 100644 index 0000000..a3fa2ac --- /dev/null +++ b/src/libostree/ostree-soup-uri.c @@ -0,0 +1,1483 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* soup-uri.c : utility functions to parse URLs */ + +/* + * Copyright 1999-2003 Ximian, Inc. + */ + +#include "config.h" + +#include +#include + +#include "ostree-soup-uri.h" + +/* OSTREECHANGE: definitions from soup-misc-private.h */ +char *soup_uri_decoded_copy (const char *str, int length, int *decoded_length); +char *soup_uri_to_string_internal (SoupURI *uri, gboolean just_path_and_query, + gboolean force_port); +gboolean soup_uri_is_http (SoupURI *uri, char **aliases); +gboolean soup_uri_is_https (SoupURI *uri, char **aliases); + +/* OSTREECHANGE: import soup-misc's char helpers */ +#define SOUP_CHAR_URI_PERCENT_ENCODED 0x01 +#define SOUP_CHAR_URI_GEN_DELIMS 0x02 +#define SOUP_CHAR_URI_SUB_DELIMS 0x04 +#define SOUP_CHAR_HTTP_SEPARATOR 0x08 +#define SOUP_CHAR_HTTP_CTL 0x10 + +/* 00 URI_UNRESERVED + * 01 URI_PCT_ENCODED + * 02 URI_GEN_DELIMS + * 04 URI_SUB_DELIMS + * 08 HTTP_SEPARATOR + * 10 HTTP_CTL + */ +const char soup_char_attributes[] = { + /* 0x00 - 0x07 */ + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + /* 0x08 - 0x0f */ + 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + /* 0x10 - 0x17 */ + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + /* 0x18 - 0x1f */ + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + /* !"#$%&' */ + 0x09, 0x04, 0x09, 0x02, 0x04, 0x01, 0x04, 0x04, + /* ()*+,-./ */ + 0x0c, 0x0c, 0x04, 0x04, 0x0c, 0x00, 0x00, 0x0a, + /* 01234567 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 89:;<=>? */ + 0x00, 0x00, 0x0a, 0x0c, 0x09, 0x0a, 0x09, 0x0a, + /* @ABCDEFG */ + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* HIJKLMNO */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* PQRSTUVW */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* XYZ[\]^_ */ + 0x00, 0x00, 0x00, 0x0a, 0x09, 0x0a, 0x01, 0x00, + /* `abcdefg */ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* hijklmno */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* pqrstuvw */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* xyz{|}~ */ + 0x00, 0x00, 0x00, 0x09, 0x01, 0x09, 0x00, 0x11, + /* 0x80 - 0xFF */ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 +}; + +#define soup_char_is_uri_percent_encoded(ch) (soup_char_attributes[(guchar)ch] & SOUP_CHAR_URI_PERCENT_ENCODED) +#define soup_char_is_uri_gen_delims(ch) (soup_char_attributes[(guchar)ch] & SOUP_CHAR_URI_GEN_DELIMS) +#define soup_char_is_uri_sub_delims(ch) (soup_char_attributes[(guchar)ch] & SOUP_CHAR_URI_SUB_DELIMS) +#define soup_char_is_uri_unreserved(ch) (!(soup_char_attributes[(guchar)ch] & (SOUP_CHAR_URI_PERCENT_ENCODED | SOUP_CHAR_URI_GEN_DELIMS | SOUP_CHAR_URI_SUB_DELIMS))) +#define soup_char_is_token(ch) (!(soup_char_attributes[(guchar)ch] & (SOUP_CHAR_HTTP_SEPARATOR | SOUP_CHAR_HTTP_CTL))) + +/** + * soup_str_case_hash: + * @key: ASCII string to hash + * + * Hashes @key in a case-insensitive manner. + * + * Return value: the hash code. + **/ +static guint +soup_str_case_hash (gconstpointer key) +{ + const char *p = key; + guint h = g_ascii_toupper(*p); + + if (h) + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + g_ascii_toupper(*p); + + return h; +} + +/** + * SECTION:soup-uri + * @short_description: URIs + * + * A #SoupURI represents a (parsed) URI. + * + * Many applications will not need to use #SoupURI directly at all; on + * the client side, soup_message_new() takes a stringified URI, and on + * the server side, the path and query components are provided for you + * in the server callback. + **/ + +/** + * SoupURI: + * @scheme: the URI scheme (eg, "http") + * @user: a username, or %NULL + * @password: a password, or %NULL + * @host: the hostname or IP address + * @port: the port number on @host + * @path: the path on @host + * @query: a query for @path, or %NULL + * @fragment: a fragment identifier within @path, or %NULL + * + * A #SoupURI represents a (parsed) URI. #SoupURI supports RFC 3986 + * (URI Generic Syntax), and can parse any valid URI. However, libsoup + * only uses "http" and "https" URIs internally; You can use + * SOUP_URI_VALID_FOR_HTTP() to test if a #SoupURI is a valid HTTP + * URI. + * + * @scheme will always be set in any URI. It is an interned string and + * is always all lowercase. (If you parse a URI with a non-lowercase + * scheme, it will be converted to lowercase.) The macros + * %SOUP_URI_SCHEME_HTTP and %SOUP_URI_SCHEME_HTTPS provide the + * interned values for "http" and "https" and can be compared against + * URI @scheme values. + * + * @user and @password are parsed as defined in the older URI specs + * (ie, separated by a colon; RFC 3986 only talks about a single + * "userinfo" field). Note that @password is not included in the + * output of soup_uri_to_string(). libsoup does not normally use these + * fields; authentication is handled via #SoupSession signals. + * + * @host contains the hostname, and @port the port specified in the + * URI. If the URI doesn't contain a hostname, @host will be %NULL, + * and if it doesn't specify a port, @port may be 0. However, for + * "http" and "https" URIs, @host is guaranteed to be non-%NULL + * (trying to parse an http URI with no @host will return %NULL), and + * @port will always be non-0 (because libsoup knows the default value + * to use when it is not specified in the URI). + * + * @path is always non-%NULL. For http/https URIs, @path will never be + * an empty string either; if the input URI has no path, the parsed + * #SoupURI will have a @path of "/". + * + * @query and @fragment are optional for all URI types. + * soup_form_decode() may be useful for parsing @query. + * + * Note that @path, @query, and @fragment may contain + * %-encoded characters. soup_uri_new() calls + * soup_uri_normalize() on them, but not soup_uri_decode(). This is + * necessary to ensure that soup_uri_to_string() will generate a URI + * that has exactly the same meaning as the original. (In theory, + * #SoupURI should leave @user, @password, and @host partially-encoded + * as well, but this would be more annoying than useful.) + **/ + +/** + * SOUP_URI_IS_VALID: + * @uri: a #SoupURI + * + * Tests whether @uri is a valid #SoupURI; that is, that it is non-%NULL + * and its @scheme and @path members are also non-%NULL. + * + * This macro does not check whether http and https URIs have a non-%NULL + * @host member. + * + * Return value: %TRUE if @uri is valid for use. + * + * Since: 2.38 + **/ + +/** + * SOUP_URI_VALID_FOR_HTTP: + * @uri: a #SoupURI + * + * Tests if @uri is a valid #SoupURI for HTTP communication; that is, if + * it can be used to construct a #SoupMessage. + * + * Return value: %TRUE if @uri is a valid "http" or "https" URI. + * + * Since: 2.24 + **/ + +/** + * SOUP_URI_SCHEME_HTTP: + * + * "http" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + */ +/** + * SOUP_URI_SCHEME_HTTPS: + * + * "https" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + */ +/** + * SOUP_URI_SCHEME_FTP: + * + * "ftp" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + * + * Since: 2.30 + */ +/** + * SOUP_URI_SCHEME_FILE: + * + * "file" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + * + * Since: 2.30 + */ +/** + * SOUP_URI_SCHEME_DATA: + * + * "data" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + * + * Since: 2.30 + */ +/** + * SOUP_URI_SCHEME_RESOURCE: + * + * "data" as an interned string; you can compare this directly to a + * #SoupURI's scheme field using + * ==. + * + * Since: 2.42 + */ +/** + * SOUP_URI_SCHEME_WS: + * + * "ws" (WebSocket) as an interned string; you can compare this + * directly to a #SoupURI's scheme field using + * ==. + * + * Since: 2.50 + */ +/** + * SOUP_URI_SCHEME_WSS: + * + * "wss" (WebSocket over TLS) as an interned string; you can compare + * this directly to a #SoupURI's scheme field using + * ==. + * + * Since: 2.50 + */ + +struct _SoupURI { + const char *scheme; + + char *user; + char *password; + + char *host; + guint port; + + char *path; + char *query; + + char *fragment; +}; + +static void append_uri_encoded (GString *str, const char *in, const char *extra_enc_chars); +static char *uri_normalized_copy (const char *str, int length, const char *unescape_extra); + +gpointer _SOUP_URI_SCHEME_HTTP, _SOUP_URI_SCHEME_HTTPS; +gpointer _SOUP_URI_SCHEME_WS, _SOUP_URI_SCHEME_WSS; +gpointer _SOUP_URI_SCHEME_FTP; +gpointer _SOUP_URI_SCHEME_FILE, _SOUP_URI_SCHEME_DATA, _SOUP_URI_SCHEME_RESOURCE; + +static inline const char * +soup_uri_parse_scheme (const char *scheme, int len) +{ + if (len == 4 && !g_ascii_strncasecmp (scheme, "http", len)) { + return SOUP_URI_SCHEME_HTTP; + } else if (len == 5 && !g_ascii_strncasecmp (scheme, "https", len)) { + return SOUP_URI_SCHEME_HTTPS; + } else if (len == 8 && !g_ascii_strncasecmp (scheme, "resource", len)) { + return SOUP_URI_SCHEME_RESOURCE; + } else if (len == 2 && !g_ascii_strncasecmp (scheme, "ws", len)) { + return SOUP_URI_SCHEME_WS; + } else if (len == 3 && !g_ascii_strncasecmp (scheme, "wss", len)) { + return SOUP_URI_SCHEME_WSS; + } else { + char *lower_scheme; + + lower_scheme = g_ascii_strdown (scheme, len); + scheme = g_intern_static_string (lower_scheme); + if (scheme != (const char *)lower_scheme) + g_free (lower_scheme); + return scheme; + } +} + +static inline guint +soup_scheme_default_port (const char *scheme) +{ + if (scheme == SOUP_URI_SCHEME_HTTP || scheme == SOUP_URI_SCHEME_WS) + return 80; + else if (scheme == SOUP_URI_SCHEME_HTTPS || scheme == SOUP_URI_SCHEME_WSS) + return 443; + else if (scheme == SOUP_URI_SCHEME_FTP) + return 21; + else + return 0; +} + +/** + * soup_uri_new_with_base: + * @base: a base URI + * @uri_string: the URI + * + * Parses @uri_string relative to @base. + * + * Return value: a parsed #SoupURI. + **/ +SoupURI * +soup_uri_new_with_base (SoupURI *base, const char *uri_string) +{ + SoupURI *uri, fixed_base; + const char *end, *hash, *colon, *at, *path, *question; + const char *p, *hostend; + gboolean remove_dot_segments = TRUE; + int len; + + g_return_val_if_fail (uri_string != NULL, NULL); + + /* Allow a %NULL path in @base, for compatibility */ + if (base && base->scheme && !base->path) { + g_warn_if_fail (SOUP_URI_IS_VALID (base)); + + memcpy (&fixed_base, base, sizeof (SoupURI)); + fixed_base.path = ""; + base = &fixed_base; + } + + g_return_val_if_fail (base == NULL || SOUP_URI_IS_VALID (base), NULL); + + /* First some cleanup steps (which are supposed to all be no-ops, + * but...). Skip initial whitespace, strip out internal tabs and + * line breaks, and ignore trailing whitespace. + */ + while (g_ascii_isspace (*uri_string)) + uri_string++; + + len = strcspn (uri_string, "\t\n\r"); + if (uri_string[len]) { + char *clean = g_malloc (strlen (uri_string) + 1), *d; + const char *s; + + for (s = uri_string, d = clean; *s; s++) { + if (*s != '\t' && *s != '\n' && *s != '\r') + *d++ = *s; + } + *d = '\0'; + + uri = soup_uri_new_with_base (base, clean); + g_free (clean); + return uri; + } + end = uri_string + len; + while (end > uri_string && g_ascii_isspace (end[-1])) + end--; + + uri = g_slice_new0 (SoupURI); + + /* Find fragment. */ + hash = strchr (uri_string, '#'); + if (hash) { + uri->fragment = uri_normalized_copy (hash + 1, end - hash + 1, + NULL); + end = hash; + } + + /* Find scheme */ + p = uri_string; + while (p < end && (g_ascii_isalpha (*p) || + (p > uri_string && (g_ascii_isdigit (*p) || + *p == '.' || + *p == '+' || + *p == '-')))) + p++; + + if (p > uri_string && *p == ':') { + uri->scheme = soup_uri_parse_scheme (uri_string, p - uri_string); + uri_string = p + 1; + } + + if (uri_string == end && !base && !uri->fragment) { + uri->path = g_strdup (""); + return uri; + } + + /* Check for authority */ + if (strncmp (uri_string, "//", 2) == 0) { + uri_string += 2; + + path = uri_string + strcspn (uri_string, "/?#"); + if (path > end) + path = end; + at = strchr (uri_string, '@'); + if (at && at < path) { + colon = strchr (uri_string, ':'); + if (colon && colon < at) { + uri->password = soup_uri_decoded_copy (colon + 1, + at - colon - 1, NULL); + } else { + uri->password = NULL; + colon = at; + } + + uri->user = soup_uri_decoded_copy (uri_string, + colon - uri_string, NULL); + uri_string = at + 1; + } else + uri->user = uri->password = NULL; + + /* Find host and port. */ + if (*uri_string == '[') { + const char *pct; + + uri_string++; + hostend = strchr (uri_string, ']'); + if (!hostend || hostend > path) { + soup_uri_free (uri); + return NULL; + } + if (*(hostend + 1) == ':') + colon = hostend + 1; + else + colon = NULL; + + pct = memchr (uri_string, '%', hostend - uri_string); + if (!pct || (pct[1] == '2' && pct[2] == '5')) { + uri->host = soup_uri_decoded_copy (uri_string, + hostend - uri_string, NULL); + } else + uri->host = g_strndup (uri_string, hostend - uri_string); + } else { + colon = memchr (uri_string, ':', path - uri_string); + hostend = colon ? colon : path; + uri->host = soup_uri_decoded_copy (uri_string, + hostend - uri_string, NULL); + } + + if (colon && colon != path - 1) { + char *portend; + uri->port = strtoul (colon + 1, &portend, 10); + if (portend != (char *)path) { + soup_uri_free (uri); + return NULL; + } + } + + uri_string = path; + } + + /* Find query */ + question = memchr (uri_string, '?', end - uri_string); + if (question) { + uri->query = uri_normalized_copy (question + 1, + end - (question + 1), + NULL); + end = question; + } + + if (end != uri_string) { + uri->path = uri_normalized_copy (uri_string, end - uri_string, + NULL); + } + + /* Apply base URI. This is spelled out in RFC 3986. */ + if (base && !uri->scheme && uri->host) + uri->scheme = base->scheme; + else if (base && !uri->scheme) { + uri->scheme = base->scheme; + uri->user = g_strdup (base->user); + uri->password = g_strdup (base->password); + uri->host = g_strdup (base->host); + uri->port = base->port; + + if (!uri->path) { + uri->path = g_strdup (base->path); + if (!uri->query) + uri->query = g_strdup (base->query); + remove_dot_segments = FALSE; + } else if (*uri->path != '/') { + char *newpath, *last; + + last = strrchr (base->path, '/'); + if (last) { + newpath = g_strdup_printf ("%.*s%s", + (int)(last + 1 - base->path), + base->path, + uri->path); + } else + newpath = g_strdup_printf ("/%s", uri->path); + + g_free (uri->path); + uri->path = newpath; + } + } + + if (remove_dot_segments && uri->path && *uri->path) { + char *p, *q; + + /* Remove "./" where "." is a complete segment. */ + for (p = uri->path + 1; *p; ) { + if (*(p - 1) == '/' && + *p == '.' && *(p + 1) == '/') + memmove (p, p + 2, strlen (p + 2) + 1); + else + p++; + } + /* Remove "." at end. */ + if (p > uri->path + 2 && + *(p - 1) == '.' && *(p - 2) == '/') + *(p - 1) = '\0'; + + /* Remove "/../" where != ".." */ + for (p = uri->path + 1; *p; ) { + if (!strncmp (p, "../", 3)) { + p += 3; + continue; + } + q = strchr (p + 1, '/'); + if (!q) + break; + if (strncmp (q, "/../", 4) != 0) { + p = q + 1; + continue; + } + memmove (p, q + 4, strlen (q + 4) + 1); + p = uri->path + 1; + } + /* Remove "/.." at end where != ".." */ + q = strrchr (uri->path, '/'); + if (q && !strcmp (q, "/..")) { + p = q - 1; + while (p > uri->path && *p != '/') + p--; + if (strncmp (p, "/../", 4) != 0) + *(p + 1) = 0; + } + + /* Remove extraneous initial "/.."s */ + while (!strncmp (uri->path, "/../", 4)) + memmove (uri->path, uri->path + 3, strlen (uri->path) - 2); + if (!strcmp (uri->path, "/..")) + uri->path[1] = '\0'; + } + + /* HTTP-specific stuff */ + if (uri->scheme == SOUP_URI_SCHEME_HTTP || + uri->scheme == SOUP_URI_SCHEME_HTTPS) { + if (!uri->path) + uri->path = g_strdup ("/"); + if (!SOUP_URI_VALID_FOR_HTTP (uri)) { + soup_uri_free (uri); + return NULL; + } + } + + if (uri->scheme == SOUP_URI_SCHEME_FTP) { + if (!uri->host) { + soup_uri_free (uri); + return NULL; + } + } + + if (!uri->port) + uri->port = soup_scheme_default_port (uri->scheme); + if (!uri->path) + uri->path = g_strdup (""); + + return uri; +} + +/** + * soup_uri_new: + * @uri_string: (allow-none): a URI + * + * Parses an absolute URI. + * + * You can also pass %NULL for @uri_string if you want to get back an + * "empty" #SoupURI that you can fill in by hand. (You will need to + * call at least soup_uri_set_scheme() and soup_uri_set_path(), since + * those fields are required.) + * + * Return value: (nullable): a #SoupURI, or %NULL if the given string + * was found to be invalid. + **/ +SoupURI * +soup_uri_new (const char *uri_string) +{ + SoupURI *uri; + + if (!uri_string) + return g_slice_new0 (SoupURI); + + uri = soup_uri_new_with_base (NULL, uri_string); + if (!uri) + return NULL; + if (!SOUP_URI_IS_VALID (uri)) { + soup_uri_free (uri); + return NULL; + } + + return uri; +} + + +char * +soup_uri_to_string_internal (SoupURI *uri, gboolean just_path_and_query, + gboolean force_port) +{ + GString *str; + char *return_result; + + g_return_val_if_fail (uri != NULL, NULL); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); + + str = g_string_sized_new (40); + + if (uri->scheme && !just_path_and_query) + g_string_append_printf (str, "%s:", uri->scheme); + if (uri->host && !just_path_and_query) { + g_string_append (str, "//"); + if (uri->user) { + append_uri_encoded (str, uri->user, ":;@?/"); + g_string_append_c (str, '@'); + } + if (strchr (uri->host, ':')) { + const char *pct; + + g_string_append_c (str, '['); + pct = strchr (uri->host, '%'); + if (pct) { + g_string_append_printf (str, "%.*s%%25%s", + (int) (pct - uri->host), + uri->host, pct + 1); + } else + g_string_append (str, uri->host); + g_string_append_c (str, ']'); + } else + append_uri_encoded (str, uri->host, ":/"); + if (uri->port && (force_port || uri->port != soup_scheme_default_port (uri->scheme))) + g_string_append_printf (str, ":%u", uri->port); + if (!uri->path && (uri->query || uri->fragment)) + g_string_append_c (str, '/'); + else if ((!uri->path || !*uri->path) && + (uri->scheme == SOUP_URI_SCHEME_HTTP || + uri->scheme == SOUP_URI_SCHEME_HTTPS)) + g_string_append_c (str, '/'); + } + + if (uri->path && *uri->path) + g_string_append (str, uri->path); + else if (just_path_and_query) + g_string_append_c (str, '/'); + + if (uri->query) { + g_string_append_c (str, '?'); + g_string_append (str, uri->query); + } + if (uri->fragment && !just_path_and_query) { + g_string_append_c (str, '#'); + g_string_append (str, uri->fragment); + } + + return_result = str->str; + g_string_free (str, FALSE); + + return return_result; +} + +/** + * soup_uri_to_string: + * @uri: a #SoupURI + * @just_path_and_query: if %TRUE, output just the path and query portions + * + * Returns a string representing @uri. + * + * If @just_path_and_query is %TRUE, this concatenates the path and query + * together. That is, it constructs the string that would be needed in + * the Request-Line of an HTTP request for @uri. + * + * Note that the output will never contain a password, even if @uri + * does. + * + * Return value: a string representing @uri, which the caller must free. + **/ +char * +soup_uri_to_string (SoupURI *uri, gboolean just_path_and_query) +{ + return soup_uri_to_string_internal (uri, just_path_and_query, FALSE); +} + +/** + * soup_uri_copy: + * @uri: a #SoupURI + * + * Copies @uri + * + * Return value: a copy of @uri, which must be freed with soup_uri_free() + **/ +SoupURI * +soup_uri_copy (SoupURI *uri) +{ + SoupURI *dup; + + g_return_val_if_fail (uri != NULL, NULL); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); + + dup = g_slice_new0 (SoupURI); + dup->scheme = uri->scheme; + dup->user = g_strdup (uri->user); + dup->password = g_strdup (uri->password); + dup->host = g_strdup (uri->host); + dup->port = uri->port; + dup->path = g_strdup (uri->path); + dup->query = g_strdup (uri->query); + dup->fragment = g_strdup (uri->fragment); + + return dup; +} + +static inline gboolean +parts_equal (const char *one, const char *two, gboolean insensitive) +{ + if (!one && !two) + return TRUE; + if (!one || !two) + return FALSE; + return insensitive ? !g_ascii_strcasecmp (one, two) : !strcmp (one, two); +} + +/** + * soup_uri_equal: + * @uri1: a #SoupURI + * @uri2: another #SoupURI + * + * Tests whether or not @uri1 and @uri2 are equal in all parts + * + * Return value: %TRUE or %FALSE + **/ +gboolean +soup_uri_equal (SoupURI *uri1, SoupURI *uri2) +{ + g_return_val_if_fail (uri1 != NULL, FALSE); + g_return_val_if_fail (uri2 != NULL, FALSE); + g_warn_if_fail (SOUP_URI_IS_VALID (uri1)); + g_warn_if_fail (SOUP_URI_IS_VALID (uri2)); + + if (uri1->scheme != uri2->scheme || + uri1->port != uri2->port || + !parts_equal (uri1->user, uri2->user, FALSE) || + !parts_equal (uri1->password, uri2->password, FALSE) || + !parts_equal (uri1->host, uri2->host, TRUE) || + !parts_equal (uri1->path, uri2->path, FALSE) || + !parts_equal (uri1->query, uri2->query, FALSE) || + !parts_equal (uri1->fragment, uri2->fragment, FALSE)) + return FALSE; + + return TRUE; +} + +/** + * soup_uri_free: + * @uri: a #SoupURI + * + * Frees @uri. + **/ +void +soup_uri_free (SoupURI *uri) +{ + g_return_if_fail (uri != NULL); + + g_free (uri->user); + g_free (uri->password); + g_free (uri->host); + g_free (uri->path); + g_free (uri->query); + g_free (uri->fragment); + + g_slice_free (SoupURI, uri); +} + +static void +append_uri_encoded (GString *str, const char *in, const char *extra_enc_chars) +{ + const unsigned char *s = (const unsigned char *)in; + + while (*s) { + if (soup_char_is_uri_percent_encoded (*s) || + soup_char_is_uri_gen_delims (*s) || + (extra_enc_chars && strchr (extra_enc_chars, *s))) + g_string_append_printf (str, "%%%02X", (int)*s++); + else + g_string_append_c (str, *s++); + } +} + +/** + * soup_uri_encode: + * @part: a URI part + * @escape_extra: (allow-none): additional reserved characters to + * escape (or %NULL) + * + * This %-encodes the given URI part and returns the escaped + * version in allocated memory, which the caller must free when it is + * done. + * + * Return value: the encoded URI part + **/ +char * +soup_uri_encode (const char *part, const char *escape_extra) +{ + GString *str; + char *encoded; + + g_return_val_if_fail (part != NULL, NULL); + + str = g_string_new (NULL); + append_uri_encoded (str, part, escape_extra); + encoded = str->str; + g_string_free (str, FALSE); + + return encoded; +} + +#define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10) +#define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2])) + +char * +soup_uri_decoded_copy (const char *part, int length, int *decoded_length) +{ + unsigned char *s, *d; + char *decoded; + + g_return_val_if_fail (part != NULL, NULL); + + decoded = g_strndup (part, length); + s = d = (unsigned char *)decoded; + do { + if (*s == '%') { + if (!g_ascii_isxdigit (s[1]) || + !g_ascii_isxdigit (s[2])) { + *d++ = *s; + continue; + } + *d++ = HEXCHAR (s); + s += 2; + } else + *d++ = *s; + } while (*s++); + + if (decoded_length) + *decoded_length = d - (unsigned char *)decoded - 1; + + return decoded; +} + +/** + * soup_uri_decode: + * @part: a URI part + * + * Fully %-decodes @part. + * + * In the past, this would return %NULL if @part contained invalid + * percent-encoding, but now it just ignores the problem (as + * soup_uri_new() already did). + * + * Return value: the decoded URI part. + */ +char * +soup_uri_decode (const char *part) +{ + g_return_val_if_fail (part != NULL, NULL); + + return soup_uri_decoded_copy (part, strlen (part), NULL); +} + +static char * +uri_normalized_copy (const char *part, int length, + const char *unescape_extra) +{ + unsigned char *s, *d, c; + char *normalized = g_strndup (part, length); + gboolean need_fixup = FALSE; + + if (!unescape_extra) + unescape_extra = ""; + + s = d = (unsigned char *)normalized; + while (*s) { + if (*s == '%') { + if (!g_ascii_isxdigit (s[1]) || + !g_ascii_isxdigit (s[2])) { + *d++ = *s++; + continue; + } + + c = HEXCHAR (s); + if (soup_char_is_uri_unreserved (c) || + (c && strchr (unescape_extra, c))) { + *d++ = c; + s += 3; + } else { + /* We leave it unchanged. We used to uppercase percent-encoded + * triplets but we do not do it any more as RFC3986 Section 6.2.2.1 + * says that they only SHOULD be case normalized. + */ + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + } else { + if (!g_ascii_isgraph (*s) && + !strchr (unescape_extra, *s)) + need_fixup = TRUE; + *d++ = *s++; + } + } + *d = '\0'; + + if (need_fixup) { + GString *fixed; + + fixed = g_string_new (NULL); + s = (guchar *)normalized; + while (*s) { + if (g_ascii_isgraph (*s) || + strchr (unescape_extra, *s)) + g_string_append_c (fixed, *s); + else + g_string_append_printf (fixed, "%%%02X", (int)*s); + s++; + } + g_free (normalized); + normalized = g_string_free (fixed, FALSE); + } + + return normalized; +} + +/** + * soup_uri_normalize: + * @part: a URI part + * @unescape_extra: (allow-none): reserved characters to unescape (or %NULL) + * + * %-decodes any "unreserved" characters (or characters in + * @unescape_extra) in @part, and %-encodes any non-ASCII + * characters, spaces, and non-printing characters in @part. + * + * "Unreserved" characters are those that are not allowed to be used + * for punctuation according to the URI spec. For example, letters are + * unreserved, so soup_uri_normalize() will turn + * http://example.com/foo/b%61r into + * http://example.com/foo/bar, which is guaranteed + * to mean the same thing. However, "/" is "reserved", so + * http://example.com/foo%2Fbar would not + * be changed, because it might mean something different to the + * server. + * + * In the past, this would return %NULL if @part contained invalid + * percent-encoding, but now it just ignores the problem (as + * soup_uri_new() already did). + * + * Return value: the normalized URI part + */ +char * +soup_uri_normalize (const char *part, const char *unescape_extra) +{ + g_return_val_if_fail (part != NULL, NULL); + + return uri_normalized_copy (part, strlen (part), unescape_extra); +} + + +/** + * soup_uri_uses_default_port: + * @uri: a #SoupURI + * + * Tests if @uri uses the default port for its scheme. (Eg, 80 for + * http.) (This only works for http, https and ftp; libsoup does not know + * the default ports of other protocols.) + * + * Return value: %TRUE or %FALSE + **/ +gboolean +soup_uri_uses_default_port (SoupURI *uri) +{ + g_return_val_if_fail (uri != NULL, FALSE); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); + + return uri->port == soup_scheme_default_port (uri->scheme); +} + +/** + * soup_uri_get_scheme: + * @uri: a #SoupURI + * + * Gets @uri's scheme. + * + * Return value: @uri's scheme. + * + * Since: 2.32 + **/ +const char * +soup_uri_get_scheme (SoupURI *uri) +{ + g_return_val_if_fail (uri != NULL, NULL); + + return uri->scheme; +} + +/** + * soup_uri_set_scheme: + * @uri: a #SoupURI + * @scheme: the URI scheme + * + * Sets @uri's scheme to @scheme. This will also set @uri's port to + * the default port for @scheme, if known. + **/ +void +soup_uri_set_scheme (SoupURI *uri, const char *scheme) +{ + g_return_if_fail (uri != NULL); + g_return_if_fail (scheme != NULL); + + uri->scheme = soup_uri_parse_scheme (scheme, strlen (scheme)); + uri->port = soup_scheme_default_port (uri->scheme); +} + +/** + * soup_uri_get_user: + * @uri: a #SoupURI + * + * Gets @uri's user. + * + * Return value: @uri's user. + * + * Since: 2.32 + **/ +const char * +soup_uri_get_user (SoupURI *uri) +{ + g_return_val_if_fail (uri != NULL, NULL); + + return uri->user; +} + +/** + * soup_uri_set_user: + * @uri: a #SoupURI + * @user: (allow-none): the username, or %NULL + * + * Sets @uri's user to @user. + **/ +void +soup_uri_set_user (SoupURI *uri, const char *user) +{ + g_return_if_fail (uri != NULL); + + g_free (uri->user); + uri->user = g_strdup (user); +} + +/** + * soup_uri_get_password: + * @uri: a #SoupURI + * + * Gets @uri's password. + * + * Return value: @uri's password. + * + * Since: 2.32 + **/ +const char * +soup_uri_get_password (SoupURI *uri) +{ + g_return_val_if_fail (uri != NULL, NULL); + + return uri->password; +} + +/** + * soup_uri_set_password: + * @uri: a #SoupURI + * @password: (allow-none): the password, or %NULL + * + * Sets @uri's password to @password. + **/ +void +soup_uri_set_password (SoupURI *uri, const char *password) +{ + g_return_if_fail (uri != NULL); + + g_free (uri->password); + uri->password = g_strdup (password); +} + +/** + * soup_uri_get_host: + * @uri: a #SoupURI + * + * Gets @uri's host. + * + * Return value: @uri's host. + * + * Since: 2.32 + **/ +const char * +soup_uri_get_host (SoupURI *uri) +{ + g_return_val_if_fail (uri != NULL, NULL); + + return uri->host; +} + +/** + * soup_uri_set_host: + * @uri: a #SoupURI + * @host: (allow-none): the hostname or IP address, or %NULL + * + * Sets @uri's host to @host. + * + * If @host is an IPv6 IP address, it should not include the brackets + * required by the URI syntax; they will be added automatically when + * converting @uri to a string. + * + * http and https URIs should not have a %NULL @host. + **/ +void +soup_uri_set_host (SoupURI *uri, const char *host) +{ + g_return_if_fail (uri != NULL); + + g_free (uri->host); + uri->host = g_strdup (host); +} + +/** + * soup_uri_get_port: + * @uri: a #SoupURI + * + * Gets @uri's port. + * + * Return value: @uri's port. + * + * Since: 2.32 + **/ +guint +soup_uri_get_port (SoupURI *uri) +{ + g_return_val_if_fail (uri != NULL, 0); + + return uri->port; +} + +/** + * soup_uri_set_port: + * @uri: a #SoupURI + * @port: the port, or 0 + * + * Sets @uri's port to @port. If @port is 0, @uri will not have an + * explicitly-specified port. + **/ +void +soup_uri_set_port (SoupURI *uri, guint port) +{ + g_return_if_fail (uri != NULL); + + uri->port = port; +} + +/** + * soup_uri_get_path: + * @uri: a #SoupURI + * + * Gets @uri's path. + * + * Return value: @uri's path. + * + * Since: 2.32 + **/ +const char * +soup_uri_get_path (SoupURI *uri) +{ + g_return_val_if_fail (uri != NULL, NULL); + + return uri->path; +} + +/** + * soup_uri_set_path: + * @uri: a #SoupURI + * @path: the non-%NULL path + * + * Sets @uri's path to @path. + **/ +void +soup_uri_set_path (SoupURI *uri, const char *path) +{ + g_return_if_fail (uri != NULL); + + /* We allow a NULL path for compatibility, but warn about it. */ + if (!path) { + g_warn_if_fail (path != NULL); + path = ""; + } + + g_free (uri->path); + uri->path = g_strdup (path); +} + +/** + * soup_uri_get_query: + * @uri: a #SoupURI + * + * Gets @uri's query. + * + * Return value: @uri's query. + * + * Since: 2.32 + **/ +const char * +soup_uri_get_query (SoupURI *uri) +{ + g_return_val_if_fail (uri != NULL, NULL); + + return uri->query; +} + +/** + * soup_uri_set_query: + * @uri: a #SoupURI + * @query: (allow-none): the query + * + * Sets @uri's query to @query. + **/ +void +soup_uri_set_query (SoupURI *uri, const char *query) +{ + g_return_if_fail (uri != NULL); + + g_free (uri->query); + uri->query = g_strdup (query); +} + +/** + * soup_uri_set_query_from_form: + * @uri: a #SoupURI + * @form: (element-type utf8 utf8) (transfer none): a #GHashTable containing HTML form + * information + * + * Sets @uri's query to the result of encoding @form according to the + * HTML form rules. See soup_form_encode_hash() for more information. + **/ +void +soup_uri_set_query_from_form (SoupURI *uri, GHashTable *form) +{ + g_return_if_fail (uri != NULL); + + g_free (uri->query); + uri->query = soup_form_encode_hash (form); +} + +/** + * soup_uri_set_query_from_fields: + * @uri: a #SoupURI + * @first_field: name of the first form field to encode into query + * @...: value of @first_field, followed by additional field names + * and values, terminated by %NULL. + * + * Sets @uri's query to the result of encoding the given form fields + * and values according to the * HTML form rules. See + * soup_form_encode() for more information. + **/ +void +soup_uri_set_query_from_fields (SoupURI *uri, + const char *first_field, + ...) +{ + va_list args; + + g_return_if_fail (uri != NULL); + + g_free (uri->query); + va_start (args, first_field); + uri->query = soup_form_encode_valist (first_field, args); + va_end (args); +} + +/** + * soup_uri_get_fragment: + * @uri: a #SoupURI + * + * Gets @uri's fragment. + * + * Return value: @uri's fragment. + * + * Since: 2.32 + **/ +const char * +soup_uri_get_fragment (SoupURI *uri) +{ + g_return_val_if_fail (uri != NULL, NULL); + + return uri->fragment; +} + +/** + * soup_uri_set_fragment: + * @uri: a #SoupURI + * @fragment: (allow-none): the fragment + * + * Sets @uri's fragment to @fragment. + **/ +void +soup_uri_set_fragment (SoupURI *uri, const char *fragment) +{ + g_return_if_fail (uri != NULL); + + g_free (uri->fragment); + uri->fragment = g_strdup (fragment); +} + +/** + * soup_uri_copy_host: + * @uri: a #SoupURI + * + * Makes a copy of @uri, considering only the protocol, host, and port + * + * Return value: the new #SoupURI + * + * Since: 2.28 + **/ +SoupURI * +soup_uri_copy_host (SoupURI *uri) +{ + SoupURI *dup; + + g_return_val_if_fail (uri != NULL, NULL); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); + + dup = soup_uri_new (NULL); + dup->scheme = uri->scheme; + dup->host = g_strdup (uri->host); + dup->port = uri->port; + dup->path = g_strdup (""); + + return dup; +} + +/** + * soup_uri_host_hash: + * @key: (type Soup.URI): a #SoupURI with a non-%NULL @host member + * + * Hashes @key, considering only the scheme, host, and port. + * + * Return value: a hash + * + * Since: 2.28 + **/ +guint +soup_uri_host_hash (gconstpointer key) +{ + const SoupURI *uri = key; + + g_return_val_if_fail (uri != NULL && uri->host != NULL, 0); + g_warn_if_fail (SOUP_URI_IS_VALID (uri)); + + return GPOINTER_TO_UINT (uri->scheme) + uri->port + + soup_str_case_hash (uri->host); +} + +/** + * soup_uri_host_equal: + * @v1: (type Soup.URI): a #SoupURI with a non-%NULL @host member + * @v2: (type Soup.URI): a #SoupURI with a non-%NULL @host member + * + * Compares @v1 and @v2, considering only the scheme, host, and port. + * + * Return value: whether or not the URIs are equal in scheme, host, + * and port. + * + * Since: 2.28 + **/ +gboolean +soup_uri_host_equal (gconstpointer v1, gconstpointer v2) +{ + const SoupURI *one = v1; + const SoupURI *two = v2; + + g_return_val_if_fail (one != NULL && two != NULL, one == two); + g_return_val_if_fail (one->host != NULL && two->host != NULL, one->host == two->host); + g_warn_if_fail (SOUP_URI_IS_VALID (one)); + g_warn_if_fail (SOUP_URI_IS_VALID (two)); + + if (one->scheme != two->scheme) + return FALSE; + if (one->port != two->port) + return FALSE; + + return g_ascii_strcasecmp (one->host, two->host) == 0; +} + +gboolean +soup_uri_is_http (SoupURI *uri, char **aliases) +{ + int i; + + if (uri->scheme == SOUP_URI_SCHEME_HTTP) + return TRUE; + else if (uri->scheme == SOUP_URI_SCHEME_HTTPS) + return FALSE; + else if (!aliases) + return FALSE; + + for (i = 0; aliases[i]; i++) { + if (uri->scheme == aliases[i]) + return TRUE; + } + + if (!aliases[1] && !strcmp (aliases[0], "*")) + return TRUE; + else + return FALSE; +} + +gboolean +soup_uri_is_https (SoupURI *uri, char **aliases) +{ + int i; + + if (uri->scheme == SOUP_URI_SCHEME_HTTPS) + return TRUE; + else if (uri->scheme == SOUP_URI_SCHEME_HTTP) + return FALSE; + else if (!aliases) + return FALSE; + + for (i = 0; aliases[i]; i++) { + if (uri->scheme == aliases[i]) + return TRUE; + } + + return FALSE; +} + +/* OSTREECHANGE: drop boxed type definition */ +/* G_DEFINE_BOXED_TYPE (SoupURI, soup_uri, soup_uri_copy, soup_uri_free) */ diff --git a/src/libostree/ostree-soup-uri.h b/src/libostree/ostree-soup-uri.h new file mode 100644 index 0000000..650b7ef --- /dev/null +++ b/src/libostree/ostree-soup-uri.h @@ -0,0 +1,147 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Copyright 1999-2002 Ximian, Inc. + */ + +/* NOTE - taken from the libsoup codebase for use by the ostree curl backend + * (yes, ironically enough). + * + * Please watch for future changes in libsoup. + */ + + +#ifndef SOUP_URI_H +#define SOUP_URI_H 1 + +/* OSTREECHANGE: make struct private + * Only include gio, and skip available definitions. + */ +#include +#define SOUP_AVAILABLE_IN_2_4 +#define SOUP_AVAILABLE_IN_2_28 +#define SOUP_AVAILABLE_IN_2_32 + +G_BEGIN_DECLS + +/* OSTREECHANGE: make struct private */ +typedef struct _SoupURI SoupURI; + +/* OSTREECHANGE: import soup-misc's interning */ +#define SOUP_VAR extern +#define _SOUP_ATOMIC_INTERN_STRING(variable, value) ((const char *)(g_atomic_pointer_get (&(variable)) ? (variable) : (g_atomic_pointer_set (&(variable), (gpointer)g_intern_static_string (value)), (variable)))) +#define SOUP_URI_SCHEME_HTTP _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_HTTP, "http") +#define SOUP_URI_SCHEME_HTTPS _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_HTTPS, "https") +#define SOUP_URI_SCHEME_FTP _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_FTP, "ftp") +#define SOUP_URI_SCHEME_FILE _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_FILE, "file") +#define SOUP_URI_SCHEME_DATA _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_DATA, "data") +#define SOUP_URI_SCHEME_RESOURCE _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_RESOURCE, "resource") +#define SOUP_URI_SCHEME_WS _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_WS, "ws") +#define SOUP_URI_SCHEME_WSS _SOUP_ATOMIC_INTERN_STRING (_SOUP_URI_SCHEME_WSS, "wss") + +/* OSTREECHANGE: import soup-form bits */ +SOUP_AVAILABLE_IN_2_4 +char *soup_form_encode_hash (GHashTable *form_data_set); +SOUP_AVAILABLE_IN_2_4 +char *soup_form_encode_valist (const char *first_field, + va_list args); + +SOUP_VAR gpointer _SOUP_URI_SCHEME_HTTP, _SOUP_URI_SCHEME_HTTPS; +SOUP_VAR gpointer _SOUP_URI_SCHEME_FTP; +SOUP_VAR gpointer _SOUP_URI_SCHEME_FILE, _SOUP_URI_SCHEME_DATA, _SOUP_URI_SCHEME_RESOURCE; +SOUP_VAR gpointer _SOUP_URI_SCHEME_WS, _SOUP_URI_SCHEME_WSS; + +SOUP_AVAILABLE_IN_2_4 +SoupURI *soup_uri_new_with_base (SoupURI *base, + const char *uri_string); +SOUP_AVAILABLE_IN_2_4 +SoupURI *soup_uri_new (const char *uri_string); + +SOUP_AVAILABLE_IN_2_4 +char *soup_uri_to_string (SoupURI *uri, + gboolean just_path_and_query); + +SOUP_AVAILABLE_IN_2_4 +SoupURI *soup_uri_copy (SoupURI *uri); + +SOUP_AVAILABLE_IN_2_4 +gboolean soup_uri_equal (SoupURI *uri1, + SoupURI *uri2); + +SOUP_AVAILABLE_IN_2_4 +void soup_uri_free (SoupURI *uri); + +SOUP_AVAILABLE_IN_2_4 +char *soup_uri_encode (const char *part, + const char *escape_extra); +SOUP_AVAILABLE_IN_2_4 +char *soup_uri_decode (const char *part); +SOUP_AVAILABLE_IN_2_4 +char *soup_uri_normalize (const char *part, + const char *unescape_extra); + +SOUP_AVAILABLE_IN_2_4 +gboolean soup_uri_uses_default_port (SoupURI *uri); + +SOUP_AVAILABLE_IN_2_32 +const char *soup_uri_get_scheme (SoupURI *uri); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_scheme (SoupURI *uri, + const char *scheme); +SOUP_AVAILABLE_IN_2_32 +const char *soup_uri_get_user (SoupURI *uri); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_user (SoupURI *uri, + const char *user); +SOUP_AVAILABLE_IN_2_32 +const char *soup_uri_get_password (SoupURI *uri); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_password (SoupURI *uri, + const char *password); +SOUP_AVAILABLE_IN_2_32 +const char *soup_uri_get_host (SoupURI *uri); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_host (SoupURI *uri, + const char *host); +SOUP_AVAILABLE_IN_2_32 +guint soup_uri_get_port (SoupURI *uri); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_port (SoupURI *uri, + guint port); +SOUP_AVAILABLE_IN_2_32 +const char *soup_uri_get_path (SoupURI *uri); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_path (SoupURI *uri, + const char *path); +SOUP_AVAILABLE_IN_2_32 +const char *soup_uri_get_query (SoupURI *uri); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_query (SoupURI *uri, + const char *query); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_query_from_form (SoupURI *uri, + GHashTable *form); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_query_from_fields (SoupURI *uri, + const char *first_field, + ...) G_GNUC_NULL_TERMINATED; +SOUP_AVAILABLE_IN_2_32 +const char *soup_uri_get_fragment (SoupURI *uri); +SOUP_AVAILABLE_IN_2_4 +void soup_uri_set_fragment (SoupURI *uri, + const char *fragment); + +SOUP_AVAILABLE_IN_2_28 +SoupURI *soup_uri_copy_host (SoupURI *uri); +SOUP_AVAILABLE_IN_2_28 +guint soup_uri_host_hash (gconstpointer key); +SOUP_AVAILABLE_IN_2_28 +gboolean soup_uri_host_equal (gconstpointer v1, + gconstpointer v2); + +#define SOUP_URI_IS_VALID(uri) ((uri) && (uri)->scheme && (uri)->path) +#define SOUP_URI_VALID_FOR_HTTP(uri) ((uri) && ((uri)->scheme == SOUP_URI_SCHEME_HTTP || (uri)->scheme == SOUP_URI_SCHEME_HTTPS) && (uri)->host && (uri)->path) + +G_END_DECLS + +#endif /*SOUP_URI_H*/ diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c new file mode 100644 index 0000000..71d978e --- /dev/null +++ b/src/libostree/ostree-sysroot-cleanup.c @@ -0,0 +1,581 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" +#include "ostree-repo-private.h" +#include "ostree-linuxfsutil.h" + +#include "ostree-sysroot-private.h" + +/* @deploydir_dfd: Directory FD for ostree/deploy + * @osname: Target osname + * @inout_deployments: All deployments in this subdir will be appended to this array + */ +gboolean +_ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd, + const char *osname, + GPtrArray *inout_deployments, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + const char *osdeploy_path = glnx_strjoina (osname, "/deploy"); + if (!ot_dfd_iter_init_allow_noent (deploydir_dfd, osdeploy_path, &dfd_iter, &exists, error)) + return FALSE; + if (!exists) + return TRUE; + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (dent->d_type != DT_DIR) + continue; + + g_autofree char *csum = NULL; + gint deployserial; + if (!_ostree_sysroot_parse_deploy_path_name (dent->d_name, &csum, &deployserial, error)) + return FALSE; + + g_ptr_array_add (inout_deployments, ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1)); + } + + return TRUE; +} + +/* Return in @out_deployments a new array of OstreeDeployment loaded from the + * filesystem state. + */ +static gboolean +list_all_deployment_directories (OstreeSysroot *self, + GPtrArray **out_deployments, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GPtrArray) ret_deployments = + g_ptr_array_new_with_free_func (g_object_unref); + + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (self->sysroot_fd, "ostree/deploy", &dfd_iter, &exists, error)) + return FALSE; + if (!exists) + return TRUE; + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (dent->d_type != DT_DIR) + continue; + + if (!_ostree_sysroot_list_deployment_dirs_for_os (dfd_iter.fd, dent->d_name, + ret_deployments, + cancellable, error)) + return FALSE; + } + + ot_transfer_out_value (out_deployments, &ret_deployments); + return TRUE; +} + +static gboolean +parse_bootdir_name (const char *name, + char **out_osname, + char **out_csum) +{ + const char *lastdash; + + if (out_osname) + *out_osname = NULL; + if (out_csum) + *out_csum = NULL; + + lastdash = strrchr (name, '-'); + + if (!lastdash) + return FALSE; + + if (!ostree_validate_checksum_string (lastdash + 1, NULL)) + return FALSE; + + if (out_osname) + *out_osname = g_strndup (name, lastdash - name); + if (out_csum) + *out_csum = g_strdup (lastdash + 1); + + return TRUE; +} + +static gboolean +list_all_boot_directories (OstreeSysroot *self, + GPtrArray **out_bootdirs, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GFile) boot_ostree = NULL; + g_autoptr(GPtrArray) ret_bootdirs = NULL; + GError *temp_error = NULL; + + boot_ostree = g_file_resolve_relative_path (self->path, "boot/ostree"); + + ret_bootdirs = g_ptr_array_new_with_free_func (g_object_unref); + + g_autoptr(GFileEnumerator) dir_enum = + g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, &temp_error); + if (!dir_enum) + { + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&temp_error); + goto done; + } + else + { + g_propagate_error (error, temp_error); + goto out; + } + } + + while (TRUE) + { + GFileInfo *file_info = NULL; + GFile *child = NULL; + const char *name; + + if (!g_file_enumerator_iterate (dir_enum, &file_info, &child, + NULL, error)) + goto out; + if (file_info == NULL) + break; + + if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) + continue; + + /* Only look at directories ending in -CHECKSUM; nothing else + * should be in here, but let's be conservative. + */ + name = g_file_info_get_name (file_info); + if (!parse_bootdir_name (name, NULL, NULL)) + continue; + + g_ptr_array_add (ret_bootdirs, g_object_ref (child)); + } + + done: + ret = TRUE; + ot_transfer_out_value (out_bootdirs, &ret_bootdirs); + out: + return ret; +} + +/* A sysroot has at most one active "boot version" (pair of version,subversion) + * out of a total of 4 possible. This function deletes from the filesystem the 3 + * other versions that aren't active. + */ +static gboolean +cleanup_other_bootversions (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + const int cleanup_bootversion = self->bootversion == 0 ? 1 : 0; + const int cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0; + /* Reusable buffer for path */ + g_autoptr(GString) buf = g_string_new (""); + + /* These directories are for the other major version */ + g_string_truncate (buf, 0); g_string_append_printf (buf, "boot/loader.%d", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.0", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.1", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + + /* And finally the other subbootversion */ + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.%d", self->bootversion, cleanup_subbootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + + return TRUE; +} + +/* Delete a deployment directory */ +gboolean +_ostree_sysroot_rmrf_deployment (OstreeSysroot *self, + OstreeDeployment *deployment, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *origin_relpath = ostree_deployment_get_origin_relpath (deployment); + g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); + struct stat stbuf; + glnx_autofd int deployment_fd = -1; + + if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, + &deployment_fd, error)) + return FALSE; + + if (!glnx_fstat (deployment_fd, &stbuf, error)) + return FALSE; + + /* This shouldn't happen, because higher levels should + * disallow having the booted deployment not in the active + * deployment list, but let's be extra safe. */ + if (stbuf.st_dev == self->root_device && + stbuf.st_ino == self->root_inode) + return TRUE; + + /* This deployment wasn't referenced, so delete it */ + if (!_ostree_linuxfs_fd_alter_immutable_flag (deployment_fd, FALSE, + cancellable, error)) + return FALSE; + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, origin_relpath, cancellable, error)) + return FALSE; + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error)) + return FALSE; + + return TRUE; +} + +/* As the bootloader configuration changes, we will have leftover deployments + * on disk. This function deletes all deployments which aren't actively + * referenced. + */ +static gboolean +cleanup_old_deployments (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + /* Gather the device/inode of the rootfs, so we can double + * check we won't delete it. + */ + struct stat root_stbuf; + if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error)) + return FALSE; + + /* Load all active deployments referenced by bootloader configuration. */ + g_autoptr(GHashTable) active_deployment_dirs = + g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); + g_autoptr(GHashTable) active_boot_checksums = + g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); + for (guint i = 0; i < self->deployments->len; i++) + { + OstreeDeployment *deployment = self->deployments->pdata[i]; + char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); + char *bootcsum = g_strdup (ostree_deployment_get_bootcsum (deployment)); + /* Transfer ownership */ + g_hash_table_replace (active_deployment_dirs, deployment_path, deployment_path); + g_hash_table_replace (active_boot_checksums, bootcsum, bootcsum); + } + + /* Find all deployment directories, both active and inactive */ + g_autoptr(GPtrArray) all_deployment_dirs = NULL; + if (!list_all_deployment_directories (self, &all_deployment_dirs, + cancellable, error)) + return FALSE; + g_assert (all_deployment_dirs); /* Pacify static analysis */ + for (guint i = 0; i < all_deployment_dirs->len; i++) + { + OstreeDeployment *deployment = all_deployment_dirs->pdata[i]; + g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); + + if (g_hash_table_lookup (active_deployment_dirs, deployment_path)) + continue; + + if (!_ostree_sysroot_rmrf_deployment (self, deployment, cancellable, error)) + return FALSE; + } + + /* Clean up boot directories */ + g_autoptr(GPtrArray) all_boot_dirs = NULL; + if (!list_all_boot_directories (self, &all_boot_dirs, + cancellable, error)) + return FALSE; + + for (guint i = 0; i < all_boot_dirs->len; i++) + { + GFile *bootdir = all_boot_dirs->pdata[i]; + g_autofree char *osname = NULL; + g_autofree char *bootcsum = NULL; + + if (!parse_bootdir_name (glnx_basename (gs_file_get_path_cached (bootdir)), + &osname, &bootcsum)) + g_assert_not_reached (); + + if (g_hash_table_lookup (active_boot_checksums, bootcsum)) + continue; + + if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (bootdir), cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/* Delete the ref bindings for a non-active boot version */ +static gboolean +cleanup_ref_prefix (OstreeRepo *repo, + int bootversion, + int subbootversion, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion); + g_autoptr(GHashTable) refs = NULL; + if (!ostree_repo_list_refs_ext (repo, prefix, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, cancellable, error)) + return FALSE; + + GLNX_HASH_TABLE_FOREACH (refs, const char *, ref) + { + if (!ostree_repo_set_ref_immediate (repo, NULL, ref, NULL, cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/* libostree holds a ref for each deployment's exact checksum to avoid it being + * GC'd even if the origin ref changes. This function resets those refs + * to match active deployments. + */ +static gboolean +generate_deployment_refs (OstreeSysroot *self, + OstreeRepo *repo, + int bootversion, + int subbootversion, + GPtrArray *deployments, + GCancellable *cancellable, + GError **error) +{ + int cleanup_bootversion = (bootversion == 0) ? 1 : 0; + int cleanup_subbootversion = (subbootversion == 0) ? 1 : 0; + + if (!cleanup_ref_prefix (repo, cleanup_bootversion, 0, + cancellable, error)) + return FALSE; + + if (!cleanup_ref_prefix (repo, cleanup_bootversion, 1, + cancellable, error)) + return FALSE; + + if (!cleanup_ref_prefix (repo, bootversion, cleanup_subbootversion, + cancellable, error)) + return FALSE; + + g_autoptr(_OstreeRepoAutoTransaction) txn = + _ostree_repo_auto_transaction_start (repo, cancellable, error); + if (!txn) + return FALSE; + for (guint i = 0; i < deployments->len; i++) + { + OstreeDeployment *deployment = deployments->pdata[i]; + g_autofree char *refname = g_strdup_printf ("ostree/%d/%d/%u", + bootversion, subbootversion, + i); + + ostree_repo_transaction_set_refspec (repo, refname, ostree_deployment_get_csum (deployment)); + } + if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_cleanup_prune_repo: + * @sysroot: Sysroot + * @options: Flags controlling pruning + * @out_objects_total: (out): Number of objects found + * @out_objects_pruned: (out): Number of objects deleted + * @out_pruned_object_size_total: (out): Storage size in bytes of objects deleted + * @cancellable: Cancellable + * @error: Error + * + * Prune the system repository. This is a thin wrapper + * around ostree_repo_prune_from_reachable(); the primary + * addition is that this function automatically gathers + * all deployed commits into the reachable set. + * + * You generally want to at least set the `OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY` + * flag in @options. A commit traversal depth of `0` is assumed. + * + * Locking: exclusive + * Since: 2018.6 + */ +gboolean +ostree_sysroot_cleanup_prune_repo (OstreeSysroot *sysroot, + OstreeRepoPruneOptions *options, + gint *out_objects_total, + gint *out_objects_pruned, + guint64 *out_pruned_object_size_total, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Pruning system repository", error); + OstreeRepo *repo = ostree_sysroot_repo (sysroot); + const guint depth = 0; /* Historical default */ + + if (!_ostree_sysroot_ensure_writable (sysroot, error)) + return FALSE; + + /* Hold an exclusive lock by default across gathering refs and doing + * the prune. + */ + g_autoptr(OstreeRepoAutoLock) lock = + _ostree_repo_auto_lock_push (repo, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error); + if (!lock) + return FALSE; + + /* Ensure reachable has refs, but default to depth 0. This is + * what we've always done for the system repo, but perhaps down + * the line we could add a depth flag to the repo config or something? + */ + if (!ostree_repo_traverse_reachable_refs (repo, depth, options->reachable, cancellable, error)) + return FALSE; + + /* Since ostree was created we've been generating "deployment refs" in + * generate_deployment_refs() that look like ostree/0/1 etc. to ensure that + * anything doing a direct prune won't delete commits backing deployments. + * This bit might allow us to eventually drop that behavior, although we'd + * have to be very careful to ensure that all software is updated to use + * `ostree_sysroot_cleanup_prune_repo()`. + */ + for (guint i = 0; i < sysroot->deployments->len; i++) + { + const char *checksum = ostree_deployment_get_csum (sysroot->deployments->pdata[i]); + if (!ostree_repo_traverse_commit_union (repo, checksum, depth, options->reachable, + cancellable, error)) + return FALSE; + } + + if (!ostree_repo_prune_from_reachable (repo, options, + out_objects_total, out_objects_pruned, + out_pruned_object_size_total, + cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_cleanup: + * @self: Sysroot + * @cancellable: Cancellable + * @error: Error + * + * Delete any state that resulted from a partially completed + * transaction, such as incomplete deployments. + */ +gboolean +ostree_sysroot_cleanup (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + return _ostree_sysroot_cleanup_internal (self, TRUE, cancellable, error); +} + +/** + * ostree_sysroot_prepare_cleanup: + * @self: Sysroot + * @cancellable: Cancellable + * @error: Error + * + * Like ostree_sysroot_cleanup() in that it cleans up incomplete deployments + * and old boot versions, but does NOT prune the repository. + */ +gboolean +ostree_sysroot_prepare_cleanup (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + return _ostree_sysroot_cleanup_internal (self, FALSE, cancellable, error); +} + +gboolean +_ostree_sysroot_cleanup_internal (OstreeSysroot *self, + gboolean do_prune_repo, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (OSTREE_IS_SYSROOT (self), FALSE); + g_return_val_if_fail (self->loadstate == OSTREE_SYSROOT_LOAD_STATE_LOADED, FALSE); + + if (!_ostree_sysroot_ensure_writable (self, error)) + return FALSE; + + if (!cleanup_other_bootversions (self, cancellable, error)) + return glnx_prefix_error (error, "Cleaning bootversions"); + + if (!cleanup_old_deployments (self, cancellable, error)) + return glnx_prefix_error (error, "Cleaning deployments"); + + OstreeRepo *repo = ostree_sysroot_repo (self); + if (!generate_deployment_refs (self, repo, + self->bootversion, + self->subbootversion, + self->deployments, + cancellable, error)) + return glnx_prefix_error (error, "Generating deployment refs"); + + if (do_prune_repo) + { + gint n_objects_total; + gint n_objects_pruned; + guint64 freed_space; + g_autoptr(GHashTable) reachable = ostree_repo_traverse_new_reachable (); + OstreeRepoPruneOptions opts = { OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY, reachable }; + if (!ostree_sysroot_cleanup_prune_repo (self, &opts, &n_objects_total, + &n_objects_pruned, &freed_space, + cancellable, error)) + return FALSE; + + /* TODO remove printf in library */ + if (freed_space > 0) + { + g_autofree char *freed_space_str = g_format_size_full (freed_space, 0); + g_print ("Freed objects: %s\n", freed_space_str); + } + } + + return TRUE; +} diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c new file mode 100644 index 0000000..cb59302 --- /dev/null +++ b/src/libostree/ostree-sysroot-deploy.c @@ -0,0 +1,3275 @@ +/* + * Copyright (C) 2012,2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBMOUNT +#include +#endif +#ifdef HAVE_LIBSYSTEMD +#include +#endif + +#include "otutil.h" +#include "ostree.h" +#include "ostree-repo-private.h" +#include "ostree-sysroot-private.h" +#include "ostree-sepolicy-private.h" +#include "ostree-bootloader-zipl.h" +#include "ostree-deployment-private.h" +#include "ostree-core-private.h" +#include "ostree-linuxfsutil.h" +#include "libglnx.h" + +#ifdef HAVE_LIBSYSTEMD +#define OSTREE_VARRELABEL_ID SD_ID128_MAKE(da,67,9b,08,ac,d3,45,04,b7,89,d9,6f,81,8e,a7,81) +#define OSTREE_CONFIGMERGE_ID SD_ID128_MAKE(d3,86,3b,ae,c1,3e,44,49,ab,03,84,68,4a,8a,f3,a7) +#define OSTREE_DEPLOYMENT_COMPLETE_ID SD_ID128_MAKE(dd,44,0e,3e,54,90,83,b6,3d,0e,fc,7d,c1,52,55,f1) +#define OSTREE_DEPLOYMENT_FINALIZING_ID SD_ID128_MAKE(e8,64,6c,d6,3d,ff,46,25,b7,79,09,a8,e7,a4,09,94) +#endif + +static gboolean +is_ro_mount (const char *path); + +/* + * Like symlinkat() but overwrites (atomically) an existing + * symlink. + */ +static gboolean +symlink_at_replace (const char *oldpath, + int parent_dfd, + const char *newpath, + GCancellable *cancellable, + GError **error) +{ + /* Possibly in the future generate a temporary random name here, + * would need to move "generate a temporary name" code into + * libglnx or glib? + */ + g_autofree char *temppath = g_strconcat (newpath, ".tmp", NULL); + + /* Clean up any stale temporary links */ + (void) unlinkat (parent_dfd, temppath, 0); + + /* Create the temp link */ + if (TEMP_FAILURE_RETRY (symlinkat (oldpath, parent_dfd, temppath)) < 0) + return glnx_throw_errno_prefix (error, "symlinkat"); + + /* Rename it into place */ + if (!glnx_renameat (parent_dfd, temppath, parent_dfd, newpath, error)) + return FALSE; + + return TRUE; +} + +static GLnxFileCopyFlags +sysroot_flags_to_copy_flags (GLnxFileCopyFlags defaults, + OstreeSysrootDebugFlags sysrootflags) +{ + if (sysrootflags & OSTREE_SYSROOT_DEBUG_NO_XATTRS) + defaults |= GLNX_FILE_COPY_NOXATTRS; + return defaults; +} + +/* Try a hardlink if we can, otherwise fall back to copying. Used + * right now for kernels/initramfs/device trees in /boot, where we can just + * hardlink if we're on the same partition. + */ +static gboolean +install_into_boot (OstreeRepo *repo, + OstreeSePolicy *sepolicy, + int src_dfd, + const char *src_subpath, + int dest_dfd, + const char *dest_subpath, + OstreeSysrootDebugFlags flags, + GCancellable *cancellable, + GError **error) +{ + if (linkat (src_dfd, src_subpath, dest_dfd, dest_subpath, 0) == 0) + return TRUE; /* Note early return */ + if (!G_IN_SET (errno, EMLINK, EXDEV)) + return glnx_throw_errno_prefix (error, "linkat(%s)", dest_subpath); + + /* Otherwise, copy */ + struct stat src_stbuf; + if (!glnx_fstatat (src_dfd, src_subpath, &src_stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + glnx_autofd int src_fd = -1; + if (!glnx_openat_rdonly (src_dfd, src_subpath, FALSE, &src_fd, error)) + return FALSE; + + /* Be sure we relabel when copying the kernel, as in current + * e.g. Fedora it might be labeled module_object_t or usr_t, + * but policy may not allow other processes to read from that + * like kdump. + * See also https://github.com/fedora-selinux/selinux-policy/commit/747f4e6775d773ab74efae5aa37f3e5e7f0d4aca + * This means we also drop xattrs but...I doubt anyone uses + * non-SELinux xattrs for the kernel anyways aside from perhaps + * IMA but that's its own story. + */ + g_auto(OstreeSepolicyFsCreatecon) fscreatecon = { 0, }; + const char *boot_path = glnx_strjoina ("/boot/", glnx_basename (dest_subpath)); + if (!_ostree_sepolicy_preparefscreatecon (&fscreatecon, sepolicy, + boot_path, S_IFREG | 0644, + error)) + return FALSE; + + g_auto(GLnxTmpfile) tmp_dest = { 0, }; + if (!glnx_open_tmpfile_linkable_at (dest_dfd, ".", O_WRONLY | O_CLOEXEC, + &tmp_dest, error)) + return FALSE; + + if (glnx_regfile_copy_bytes (src_fd, tmp_dest.fd, (off_t) -1) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); + + /* Kernel data should always be root-owned */ + if (fchown (tmp_dest.fd, src_stbuf.st_uid, src_stbuf.st_gid) != 0) + return glnx_throw_errno_prefix (error, "fchown"); + + if (fchmod (tmp_dest.fd, src_stbuf.st_mode & 07777) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + if (fdatasync (tmp_dest.fd) < 0) + return glnx_throw_errno_prefix (error, "fdatasync"); + + /* Today we don't have a config flag to *require* verity on /boot, + * and at least for Fedora CoreOS we're not likely to do fsverity on + * /boot soon due to wanting to support mounting it from old Linux + * kernels. So change "required" to "maybe". + */ + _OstreeFeatureSupport boot_verity = _OSTREE_FEATURE_NO; + if (repo->fs_verity_wanted != _OSTREE_FEATURE_NO) + boot_verity = _OSTREE_FEATURE_MAYBE; + if (!_ostree_tmpf_fsverity_core (&tmp_dest, boot_verity, NULL, error)) + return FALSE; + + if (!glnx_link_tmpfile_at (&tmp_dest, GLNX_LINK_TMPFILE_NOREPLACE, dest_dfd, dest_subpath, error)) + return FALSE; + + return TRUE; +} + +/* Copy ownership, mode, and xattrs from source directory to destination */ +static gboolean +dirfd_copy_attributes_and_xattrs (int src_parent_dfd, + const char *src_name, + int src_dfd, + int dest_dfd, + OstreeSysrootDebugFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) xattrs = NULL; + + /* Clone all xattrs first, so we get the SELinux security context + * right. This will allow other users access if they have ACLs, but + * oh well. + */ + if (!(flags & OSTREE_SYSROOT_DEBUG_NO_XATTRS)) + { + if (!glnx_dfd_name_get_all_xattrs (src_parent_dfd, src_name, + &xattrs, cancellable, error)) + return FALSE; + if (!glnx_fd_set_all_xattrs (dest_dfd, xattrs, + cancellable, error)) + return FALSE; + } + + struct stat src_stbuf; + if (!glnx_fstat (src_dfd, &src_stbuf, error)) + return FALSE; + if (fchown (dest_dfd, src_stbuf.st_uid, src_stbuf.st_gid) != 0) + return glnx_throw_errno_prefix (error, "fchown"); + if (fchmod (dest_dfd, src_stbuf.st_mode) != 0) + return glnx_throw_errno_prefix (error, "fchmod"); + + return TRUE; +} + +static gint +str_sort_cb (gconstpointer name_ptr_a, gconstpointer name_ptr_b) +{ + const gchar *name_a = *((const gchar **) name_ptr_a); + const gchar *name_b = *((const gchar **) name_ptr_b); + + return g_strcmp0 (name_a, name_b); +} + +static gboolean +checksum_dir_recurse (int dfd, + const char *path, + OtChecksum *checksum, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) dfditer = { 0, }; + g_autoptr (GPtrArray) d_entries = g_ptr_array_new_with_free_func (g_free); + + if (!glnx_dirfd_iterator_init_at (dfd, path, TRUE, &dfditer, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent (&dfditer, &dent, cancellable, error)) + return FALSE; + + if (dent == NULL) + break; + + g_ptr_array_add (d_entries, g_strdup (dent->d_name)); + } + + /* File systems do not guarantee dir entry order, make sure this is + * reproducable + */ + g_ptr_array_sort(d_entries, str_sort_cb); + + for (gint i=0; i < d_entries->len; i++) + { + const gchar *d_name = (gchar *)g_ptr_array_index (d_entries, i); + struct stat stbuf; + + if (!glnx_fstatat (dfditer.fd, d_name, &stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + if (S_ISDIR (stbuf.st_mode)) + { + if (!checksum_dir_recurse(dfditer.fd, d_name, checksum, cancellable, error)) + return FALSE; + } + else + { + int fd; + + if (!ot_openat_ignore_enoent (dfditer.fd, d_name, &fd, error)) + return FALSE; + if (fd != -1) + { + g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) + return FALSE; + } + } + + } + + return TRUE; +} + +static gboolean +copy_dir_recurse (int src_parent_dfd, + int dest_parent_dfd, + const char *name, + OstreeSysrootDebugFlags flags, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) src_dfd_iter = { 0, }; + glnx_autofd int dest_dfd = -1; + struct dirent *dent; + + if (!glnx_dirfd_iterator_init_at (src_parent_dfd, name, TRUE, &src_dfd_iter, error)) + return FALSE; + + /* Create with mode 0700, we'll fchmod/fchown later */ + if (!glnx_ensure_dir (dest_parent_dfd, name, 0700, error)) + return FALSE; + + if (!glnx_opendirat (dest_parent_dfd, name, TRUE, &dest_dfd, error)) + return FALSE; + + if (!dirfd_copy_attributes_and_xattrs (src_parent_dfd, name, src_dfd_iter.fd, dest_dfd, + flags, cancellable, error)) + return FALSE; + + while (TRUE) + { + struct stat child_stbuf; + + if (!glnx_dirfd_iterator_next_dent (&src_dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (!glnx_fstatat (src_dfd_iter.fd, dent->d_name, &child_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + if (S_ISDIR (child_stbuf.st_mode)) + { + if (!copy_dir_recurse (src_dfd_iter.fd, dest_dfd, dent->d_name, + flags, cancellable, error)) + return FALSE; + } + else + { + if (!glnx_file_copy_at (src_dfd_iter.fd, dent->d_name, &child_stbuf, + dest_dfd, dent->d_name, + sysroot_flags_to_copy_flags (GLNX_FILE_COPY_OVERWRITE, flags), + cancellable, error)) + return FALSE; + } + } + + return TRUE; +} + +/* If a chain of directories is added, this function will ensure + * they're created. + */ +static gboolean +ensure_directory_from_template (int orig_etc_fd, + int modified_etc_fd, + int new_etc_fd, + const char *path, + int *out_dfd, + OstreeSysrootDebugFlags flags, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int src_dfd = -1; + glnx_autofd int target_dfd = -1; + + g_assert (path != NULL); + g_assert (*path != '/' && *path != '\0'); + + if (!glnx_opendirat (modified_etc_fd, path, TRUE, &src_dfd, error)) + return FALSE; + + /* Create with mode 0700, we'll fchmod/fchown later */ + again: + if (mkdirat (new_etc_fd, path, 0700) != 0) + { + if (errno == EEXIST) + { + /* Fall through */ + } + else if (errno == ENOENT) + { + g_autofree char *parent_path = g_path_get_dirname (path); + + if (strcmp (parent_path, ".") != 0) + { + if (!ensure_directory_from_template (orig_etc_fd, modified_etc_fd, new_etc_fd, + parent_path, NULL, flags, cancellable, error)) + return FALSE; + + /* Loop */ + goto again; + } + else + { + /* Fall through...shouldn't happen, but we'll propagate + * an error from open. */ + } + } + else + return glnx_throw_errno_prefix (error, "mkdirat"); + } + + if (!glnx_opendirat (new_etc_fd, path, TRUE, &target_dfd, error)) + return FALSE; + + if (!dirfd_copy_attributes_and_xattrs (modified_etc_fd, path, src_dfd, target_dfd, + flags, cancellable, error)) + return FALSE; + + if (out_dfd) + *out_dfd = glnx_steal_fd (&target_dfd); + return TRUE; +} + +/* Copy (relative) @path from @modified_etc_fd to @new_etc_fd, overwriting any + * existing file there. The @path may refer to a regular file, a symbolic link, + * or a directory. Directories will be copied recursively. + */ +static gboolean +copy_modified_config_file (int orig_etc_fd, + int modified_etc_fd, + int new_etc_fd, + const char *path, + OstreeSysrootDebugFlags flags, + GCancellable *cancellable, + GError **error) +{ + struct stat modified_stbuf; + struct stat new_stbuf; + + if (!glnx_fstatat (modified_etc_fd, path, &modified_stbuf, AT_SYMLINK_NOFOLLOW, error)) + return glnx_prefix_error (error, "Reading modified config file"); + + glnx_autofd int dest_parent_dfd = -1; + if (strchr (path, '/') != NULL) + { + g_autofree char *parent = g_path_get_dirname (path); + + if (!ensure_directory_from_template (orig_etc_fd, modified_etc_fd, new_etc_fd, + parent, &dest_parent_dfd, flags, cancellable, error)) + return FALSE; + } + else + { + dest_parent_dfd = dup (new_etc_fd); + if (dest_parent_dfd == -1) + return glnx_throw_errno_prefix (error, "dup"); + } + + g_assert (dest_parent_dfd != -1); + + if (fstatat (new_etc_fd, path, &new_stbuf, AT_SYMLINK_NOFOLLOW) < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "fstatat"); + } + else if (S_ISDIR(new_stbuf.st_mode)) + { + if (!S_ISDIR(modified_stbuf.st_mode)) + { + return g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Modified config file newly defaults to directory '%s', cannot merge", + path), FALSE; + } + else + { + /* Do nothing here - we assume that we've already + * recursively copied the parent directory. + */ + return TRUE; + } + } + else + { + if (!glnx_unlinkat (new_etc_fd, path, 0, error)) + return FALSE; + } + + if (S_ISDIR (modified_stbuf.st_mode)) + { + if (!copy_dir_recurse (modified_etc_fd, new_etc_fd, path, flags, + cancellable, error)) + return FALSE; + } + else if (S_ISLNK (modified_stbuf.st_mode) || S_ISREG (modified_stbuf.st_mode)) + { + if (!glnx_file_copy_at (modified_etc_fd, path, &modified_stbuf, + new_etc_fd, path, + sysroot_flags_to_copy_flags (GLNX_FILE_COPY_OVERWRITE, flags), + cancellable, error)) + return FALSE; + } + else + { + return glnx_throw (error, + "Unsupported non-regular/non-symlink file in /etc '%s'", + path); + } + + return TRUE; +} + +/* + * merge_configuration_from: + * @sysroot: Sysroot + * @merge_deployment: Source of configuration differences + * @new_deployment: Target for merge of configuration + * @new_deployment_dfd: Directory fd for @new_deployment (may *not* be -1) + * @cancellable: Cancellable + * @error: Error + * + * Compute the difference between @merge_deployment's `/usr/etc` and `/etc`, and + * apply that to @new_deployment's `/etc`. + * + * The algorithm for computing the difference is pretty simple; it's + * approximately equivalent to "diff -unR orig_etc modified_etc", + * except that rather than attempting a 3-way merge if a file is also + * changed in @new_etc, the modified version always wins. + */ +static gboolean +merge_configuration_from (OstreeSysroot *sysroot, + OstreeDeployment *merge_deployment, + OstreeDeployment *new_deployment, + int new_deployment_dfd, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("During /etc merge", error); + const OstreeSysrootDebugFlags flags = sysroot->debug_flags; + + g_assert (merge_deployment != NULL && new_deployment != NULL); + g_assert (new_deployment_dfd != -1); + + g_autofree char *merge_deployment_path = ostree_sysroot_get_deployment_dirpath (sysroot, merge_deployment); + glnx_autofd int merge_deployment_dfd = -1; + if (!glnx_opendirat (sysroot->sysroot_fd, merge_deployment_path, FALSE, + &merge_deployment_dfd, error)) + return FALSE; + + /* TODO: get rid of GFile usage here */ + g_autoptr(GFile) orig_etc = ot_fdrel_to_gfile (merge_deployment_dfd, "usr/etc"); + g_autoptr(GFile) modified_etc = ot_fdrel_to_gfile (merge_deployment_dfd, "etc"); + /* Return values for below */ + g_autoptr(GPtrArray) modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref); + g_autoptr(GPtrArray) removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_autoptr(GPtrArray) added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + /* For now, ignore changes to xattrs; the problem is that + * security.selinux will be different between the /usr/etc labels + * and the ones in the real /etc, so they all show up as different. + * + * This means that if you want to change the security context of a + * file, to have that change persist across upgrades, you must also + * modify the content of the file. + */ + if (!ostree_diff_dirs (OSTREE_DIFF_FLAGS_IGNORE_XATTRS, + orig_etc, modified_etc, modified, removed, added, + cancellable, error)) + return glnx_prefix_error (error, "While computing configuration diff"); + + { g_autofree char *msg = + g_strdup_printf ("Copying /etc changes: %u modified, %u removed, %u added", + modified->len, removed->len, added->len); + ot_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_CONFIGMERGE_ID), + "MESSAGE=%s", msg, + "ETC_N_MODIFIED=%u", modified->len, + "ETC_N_REMOVED=%u", removed->len, + "ETC_N_ADDED=%u", added->len, + NULL); + _ostree_sysroot_emit_journal_msg (sysroot, msg); + } + + glnx_autofd int orig_etc_fd = -1; + if (!glnx_opendirat (merge_deployment_dfd, "usr/etc", TRUE, &orig_etc_fd, error)) + return FALSE; + glnx_autofd int modified_etc_fd = -1; + if (!glnx_opendirat (merge_deployment_dfd, "etc", TRUE, &modified_etc_fd, error)) + return FALSE; + glnx_autofd int new_etc_fd = -1; + if (!glnx_opendirat (new_deployment_dfd, "etc", TRUE, &new_etc_fd, error)) + return FALSE; + + for (guint i = 0; i < removed->len; i++) + { + GFile *file = removed->pdata[i]; + g_autofree char *path = NULL; + + path = g_file_get_relative_path (orig_etc, file); + g_assert (path); + + if (!glnx_shutil_rm_rf_at (new_etc_fd, path, cancellable, error)) + return FALSE; + } + + for (guint i = 0; i < modified->len; i++) + { + OstreeDiffItem *diff = modified->pdata[i]; + g_autofree char *path = g_file_get_relative_path (modified_etc, diff->target); + + g_assert (path); + + if (!copy_modified_config_file (orig_etc_fd, modified_etc_fd, new_etc_fd, path, + flags, cancellable, error)) + return FALSE; + } + for (guint i = 0; i < added->len; i++) + { + GFile *file = added->pdata[i]; + g_autofree char *path = g_file_get_relative_path (modified_etc, file); + + g_assert (path); + + if (!copy_modified_config_file (orig_etc_fd, modified_etc_fd, new_etc_fd, path, + flags, cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/* Look up @revision in the repository, and check it out in + * /ostree/deploy/OS/deploy/${treecsum}.${deployserial}. + * A dfd for the result is returned in @out_deployment_dfd. + */ +static gboolean +checkout_deployment_tree (OstreeSysroot *sysroot, + OstreeRepo *repo, + OstreeDeployment *deployment, + int *out_deployment_dfd, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Checking out deployment tree", error); + /* Find the directory with deployments for this stateroot */ + g_autofree char *osdeploy_path = + g_strconcat ("ostree/deploy/", ostree_deployment_get_osname (deployment), "/deploy", NULL); + if (!glnx_shutil_mkdir_p_at (sysroot->sysroot_fd, osdeploy_path, 0775, cancellable, error)) + return FALSE; + + glnx_autofd int osdeploy_dfd = -1; + if (!glnx_opendirat (sysroot->sysroot_fd, osdeploy_path, TRUE, &osdeploy_dfd, error)) + return FALSE; + + /* Clean up anything that was there before, from e.g. an interrupted checkout */ + const char *csum = ostree_deployment_get_csum (deployment); + g_autofree char *checkout_target_name = + g_strdup_printf ("%s.%d", csum, ostree_deployment_get_deployserial (deployment)); + if (!glnx_shutil_rm_rf_at (osdeploy_dfd, checkout_target_name, cancellable, error)) + return FALSE; + + /* Generate hardlink farm, then opendir it */ + OstreeRepoCheckoutAtOptions checkout_opts = { 0, }; + if (!ostree_repo_checkout_at (repo, &checkout_opts, osdeploy_dfd, + checkout_target_name, csum, + cancellable, error)) + return FALSE; + + return glnx_opendirat (osdeploy_dfd, checkout_target_name, TRUE, out_deployment_dfd, + error); +} + +static char * +ptrarray_path_join (GPtrArray *path) +{ + GString *path_buf; + + path_buf = g_string_new (""); + + if (path->len == 0) + g_string_append_c (path_buf, '/'); + else + { + guint i; + for (i = 0; i < path->len; i++) + { + const char *elt = path->pdata[i]; + + g_string_append_c (path_buf, '/'); + g_string_append (path_buf, elt); + } + } + + return g_string_free (path_buf, FALSE); +} + +static gboolean +relabel_one_path (OstreeSysroot *sysroot, + OstreeSePolicy *sepolicy, + GFile *path, + GFileInfo *info, + GPtrArray *path_parts, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autofree char *relpath = NULL; + + relpath = ptrarray_path_join (path_parts); + if (!ostree_sepolicy_restorecon (sepolicy, relpath, + info, path, + OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL, + NULL, + cancellable, error)) + goto out; + + ret = TRUE; + out: + return ret; +} + +static gboolean +relabel_recursively (OstreeSysroot *sysroot, + OstreeSePolicy *sepolicy, + GFile *dir, + GFileInfo *dir_info, + GPtrArray *path_parts, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GFileEnumerator) direnum = NULL; + + if (!relabel_one_path (sysroot, sepolicy, dir, dir_info, path_parts, + cancellable, error)) + goto out; + + direnum = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!direnum) + goto out; + + while (TRUE) + { + GFileInfo *file_info; + GFile *child; + GFileType ftype; + + if (!g_file_enumerator_iterate (direnum, &file_info, &child, + cancellable, error)) + goto out; + if (file_info == NULL) + break; + + g_ptr_array_add (path_parts, (char*)g_file_info_get_name (file_info)); + + ftype = g_file_info_get_file_type (file_info); + if (ftype == G_FILE_TYPE_DIRECTORY) + { + if (!relabel_recursively (sysroot, sepolicy, child, file_info, path_parts, + cancellable, error)) + goto out; + } + else + { + if (!relabel_one_path (sysroot, sepolicy, child, file_info, path_parts, + cancellable, error)) + goto out; + } + + g_ptr_array_remove_index (path_parts, path_parts->len - 1); + } + + ret = TRUE; + out: + return ret; +} + +static gboolean +selinux_relabel_dir (OstreeSysroot *sysroot, + OstreeSePolicy *sepolicy, + GFile *dir, + const char *prefix, + GCancellable *cancellable, + GError **error) +{ + + g_autoptr(GFileInfo) root_info = + g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!root_info) + return FALSE; + + g_autoptr(GPtrArray) path_parts = g_ptr_array_new (); + g_ptr_array_add (path_parts, (char*)prefix); + if (!relabel_recursively (sysroot, sepolicy, dir, root_info, path_parts, + cancellable, error)) + return glnx_prefix_error (error, "Relabeling /%s", prefix); + + return TRUE; +} + +/* Handles SELinux labeling for /var; this is slated to be deleted. See + * https://github.com/ostreedev/ostree/pull/872 + */ +static gboolean +selinux_relabel_var_if_needed (OstreeSysroot *sysroot, + OstreeSePolicy *sepolicy, + int os_deploy_dfd, + GCancellable *cancellable, + GError **error) +{ + /* This is a bit of a hack; we should change the code at some + * point in the distant future to only create (and label) /var + * when doing a deployment. + */ + const char selabeled[] = "var/.ostree-selabeled"; + struct stat stbuf; + if (!glnx_fstatat_allow_noent (os_deploy_dfd, selabeled, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == ENOENT) + { + { g_autofree char *msg = + g_strdup_printf ("Relabeling /var (no stamp file '%s' found)", selabeled); + ot_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_VARRELABEL_ID), + "MESSAGE=%s", msg, + NULL); + _ostree_sysroot_emit_journal_msg (sysroot, msg); + } + + g_autoptr(GFile) deployment_var_path = ot_fdrel_to_gfile (os_deploy_dfd, "var"); + if (!selinux_relabel_dir (sysroot, sepolicy, + deployment_var_path, "var", + cancellable, error)) + { + g_prefix_error (error, "Relabeling /var: "); + return FALSE; + } + + { g_auto(OstreeSepolicyFsCreatecon) con = { 0, }; + const char *selabeled_abspath = glnx_strjoina ("/", selabeled); + + if (!_ostree_sepolicy_preparefscreatecon (&con, sepolicy, + selabeled_abspath, + 0644, error)) + return FALSE; + + if (!glnx_file_replace_contents_at (os_deploy_dfd, selabeled, (guint8*)"", 0, + GLNX_FILE_REPLACE_DATASYNC_NEW, + cancellable, error)) + return FALSE; + } + } + + return TRUE; +} + +/* Handle initial creation of /etc in the deployment. See also + * merge_configuration_from(). + */ +static gboolean +prepare_deployment_etc (OstreeSysroot *sysroot, + OstreeRepo *repo, + OstreeDeployment *deployment, + int deployment_dfd, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Preparing /etc", error); + + struct stat stbuf; + if (!glnx_fstatat_allow_noent (deployment_dfd, "etc", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + gboolean etc_exists = (errno == 0); + if (!glnx_fstatat_allow_noent (deployment_dfd, "usr/etc", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + gboolean usretc_exists = (errno == 0); + + if (etc_exists) + { + if (usretc_exists) + return glnx_throw (error, "Tree contains both /etc and /usr/etc"); + /* Compatibility hack */ + if (!glnx_renameat (deployment_dfd, "etc", deployment_dfd, "usr/etc", error)) + return FALSE; + usretc_exists = TRUE; + } + + if (usretc_exists) + { + /* We need copies of /etc from /usr/etc (so admins can use vi), and if + * SELinux is enabled, we need to relabel. + */ + OstreeRepoCheckoutAtOptions etc_co_opts = { .force_copy = TRUE, + .subpath = "/usr/etc", + .sepolicy_prefix = "/etc"}; + + /* Here, we initialize SELinux policy from the /usr/etc inside + * the root - this is before we've finalized the configuration + * merge into /etc. */ + g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error); + if (!sepolicy) + return FALSE; + if (ostree_sepolicy_get_name (sepolicy) != NULL) + etc_co_opts.sepolicy = sepolicy; + + /* Copy usr/etc → etc */ + if (!ostree_repo_checkout_at (repo, &etc_co_opts, + deployment_dfd, "etc", + ostree_deployment_get_csum (deployment), + cancellable, error)) + return FALSE; + + } + + return TRUE; +} + +/* Write the origin file for a deployment; this does not bump the mtime, under + * the assumption the caller may be writing multiple. + */ +static gboolean +write_origin_file_internal (OstreeSysroot *sysroot, + OstreeSePolicy *sepolicy, + OstreeDeployment *deployment, + GKeyFile *new_origin, + GLnxFileReplaceFlags flags, + GCancellable *cancellable, + GError **error) +{ + if (!_ostree_sysroot_ensure_writable (sysroot, error)) + return FALSE; + + GLNX_AUTO_PREFIX_ERROR ("Writing out origin file", error); + GKeyFile *origin = + new_origin ? new_origin : ostree_deployment_get_origin (deployment); + + if (origin) + { + g_auto(OstreeSepolicyFsCreatecon) con = { 0, }; + if (!_ostree_sepolicy_preparefscreatecon (&con, sepolicy, + "/etc/ostree/remotes.d/dummy.conf", + 0644, error)) + return FALSE; + + g_autofree char *origin_path = + g_strdup_printf ("ostree/deploy/%s/deploy/%s.%d.origin", + ostree_deployment_get_osname (deployment), + ostree_deployment_get_csum (deployment), + ostree_deployment_get_deployserial (deployment)); + + gsize len; + g_autofree char *contents = g_key_file_to_data (origin, &len, error); + if (!contents) + return FALSE; + + if (!glnx_file_replace_contents_at (sysroot->sysroot_fd, + origin_path, (guint8*)contents, len, + flags, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_sysroot_write_origin_file: + * @sysroot: System root + * @deployment: Deployment + * @new_origin: (allow-none): Origin content + * @cancellable: Cancellable + * @error: Error + * + * Immediately replace the origin file of the referenced @deployment + * with the contents of @new_origin. If @new_origin is %NULL, + * this function will write the current origin of @deployment. + */ +gboolean +ostree_sysroot_write_origin_file (OstreeSysroot *sysroot, + OstreeDeployment *deployment, + GKeyFile *new_origin, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GFile) rootfs = g_file_new_for_path ("/"); + g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new (rootfs, cancellable, error); + if (!sepolicy) + return FALSE; + + if (!write_origin_file_internal (sysroot, sepolicy, deployment, new_origin, + GLNX_FILE_REPLACE_DATASYNC_NEW, + cancellable, error)) + return FALSE; + + if (!_ostree_sysroot_bump_mtime (sysroot, error)) + return FALSE; + + return TRUE; +} + +typedef struct { + int boot_dfd; + char *kernel_srcpath; + char *kernel_namever; + char *kernel_hmac_srcpath; + char *kernel_hmac_namever; + char *initramfs_srcpath; + char *initramfs_namever; + char *devicetree_srcpath; + char *devicetree_namever; + char *bootcsum; +} OstreeKernelLayout; +static void +_ostree_kernel_layout_free (OstreeKernelLayout *layout) +{ + glnx_close_fd (&layout->boot_dfd); + g_free (layout->kernel_srcpath); + g_free (layout->kernel_namever); + g_free (layout->kernel_hmac_srcpath); + g_free (layout->kernel_hmac_namever); + g_free (layout->initramfs_srcpath); + g_free (layout->initramfs_namever); + g_free (layout->devicetree_srcpath); + g_free (layout->devicetree_namever); + g_free (layout->bootcsum); + g_free (layout); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeKernelLayout, _ostree_kernel_layout_free); + +static OstreeKernelLayout* +_ostree_kernel_layout_new (void) +{ + OstreeKernelLayout *ret = g_new0 (OstreeKernelLayout, 1); + ret->boot_dfd = -1; + return ret; +} + +/* See get_kernel_from_tree() below */ +static gboolean +get_kernel_from_tree_usrlib_modules (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *kver = NULL; + /* Look in usr/lib/modules */ + g_auto(GLnxDirFdIterator) mod_dfditer = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (deployment_dfd, "usr/lib/modules", &mod_dfditer, + &exists, error)) + return FALSE; + if (!exists) + { + /* No usr/lib/modules? We're done */ + *out_layout = NULL; + return TRUE; + } + + g_autoptr(OstreeKernelLayout) ret_layout = _ostree_kernel_layout_new (); + + /* Reusable buffer for path string */ + g_autoptr(GString) pathbuf = g_string_new (""); + /* Loop until we find something that looks like a valid /usr/lib/modules/$kver */ + while (ret_layout->boot_dfd == -1) + { + struct dirent *dent; + struct stat stbuf; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&mod_dfditer, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + if (dent->d_type != DT_DIR) + continue; + + /* It's a directory, look for /vmlinuz as a regular file */ + g_string_truncate (pathbuf, 0); + g_string_append_printf (pathbuf, "%s/vmlinuz", dent->d_name); + if (fstatat (mod_dfditer.fd, pathbuf->str, &stbuf, 0) < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "fstatat(%s)", pathbuf->str); + else + continue; + } + else + { + /* Not a regular file? Loop again */ + if (!S_ISREG (stbuf.st_mode)) + continue; + } + + /* Looks valid, this should exit the loop */ + if (!glnx_opendirat (mod_dfditer.fd, dent->d_name, FALSE, &ret_layout->boot_dfd, error)) + return FALSE; + kver = g_strdup (dent->d_name); + ret_layout->kernel_srcpath = g_strdup ("vmlinuz"); + ret_layout->kernel_namever = g_strdup_printf ("vmlinuz-%s", kver); + } + + if (ret_layout->boot_dfd == -1) + { + *out_layout = NULL; + /* No kernel found? We're done. */ + return TRUE; + } + + /* We found a module directory, compute the checksum */ + g_auto(OtChecksum) checksum = { 0, }; + ot_checksum_init (&checksum); + glnx_autofd int fd = -1; + /* Checksum the kernel */ + if (!glnx_openat_rdonly (ret_layout->boot_dfd, "vmlinuz", TRUE, &fd, error)) + return FALSE; + g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error)) + return FALSE; + g_clear_object (&in); + glnx_close_fd (&fd); + + /* Look for an initramfs, but it's optional; since there wasn't any precedent + * for this, let's be a bit conservative and support both `initramfs.img` and + * `initramfs`. + */ + const char *initramfs_paths[] = {"initramfs.img", "initramfs"}; + const char *initramfs_path = NULL; + for (guint i = 0; i < G_N_ELEMENTS(initramfs_paths); i++) + { + initramfs_path = initramfs_paths[i]; + if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, initramfs_path, &fd, error)) + return FALSE; + if (fd != -1) + break; + else + initramfs_path = NULL; + } + if (fd != -1) + { + g_assert (initramfs_path); + ret_layout->initramfs_srcpath = g_strdup (initramfs_path); + ret_layout->initramfs_namever = g_strdup_printf ("initramfs-%s.img", kver); + in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error)) + return FALSE; + } + g_clear_object (&in); + glnx_close_fd (&fd); + + /* Check for /usr/lib/modules/$kver/devicetree first, if it does not + * exist check for /usr/lib/modules/$kver/dtb/ directory. + */ + if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "devicetree", &fd, error)) + return FALSE; + if (fd != -1) + { + ret_layout->devicetree_srcpath = g_strdup ("devicetree"); + ret_layout->devicetree_namever = g_strdup_printf ("devicetree-%s", kver); + in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error)) + return FALSE; + } + else + { + struct stat stbuf; + /* Check for dtb directory */ + if (!glnx_fstatat_allow_noent (ret_layout->boot_dfd, "dtb", &stbuf, 0, error)) + return FALSE; + + if (errno == 0 && S_ISDIR (stbuf.st_mode)) + { + /* devicetree_namever set to NULL indicates a complete directory */ + ret_layout->devicetree_srcpath = g_strdup ("dtb"); + ret_layout->devicetree_namever = NULL; + + if (!checksum_dir_recurse(ret_layout->boot_dfd, "dtb", &checksum, cancellable, error)) + return FALSE; + } + } + + g_clear_object (&in); + glnx_close_fd (&fd); + + /* And finally, look for any HMAC file. This is needed for FIPS mode on some distros. */ + if (!glnx_fstatat_allow_noent (ret_layout->boot_dfd, ".vmlinuz.hmac", NULL, 0, error)) + return FALSE; + if (errno == 0) + { + ret_layout->kernel_hmac_srcpath = g_strdup (".vmlinuz.hmac"); + /* Name it as dracut expects it: https://github.com/dracutdevs/dracut/blob/225e4b94cbdb702cf512490dcd2ad9ca5f5b22c1/modules.d/01fips/fips.sh#L129 */ + ret_layout->kernel_hmac_namever = g_strdup_printf (".%s.hmac", ret_layout->kernel_namever); + } + + char hexdigest[OSTREE_SHA256_STRING_LEN+1]; + ot_checksum_get_hexdigest (&checksum, hexdigest, sizeof (hexdigest)); + ret_layout->bootcsum = g_strdup (hexdigest); + + *out_layout = g_steal_pointer (&ret_layout); + return TRUE; +} + +/* See get_kernel_from_tree() below */ +static gboolean +get_kernel_from_tree_legacy_layouts (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + const char *legacy_paths[] = {"usr/lib/ostree-boot", "boot"}; + g_autofree char *kernel_checksum = NULL; + g_autofree char *initramfs_checksum = NULL; + g_autofree char *devicetree_checksum = NULL; + g_autoptr(OstreeKernelLayout) ret_layout = _ostree_kernel_layout_new (); + + for (guint i = 0; i < G_N_ELEMENTS (legacy_paths); i++) + { + const char *path = legacy_paths[i]; + ret_layout->boot_dfd = glnx_opendirat_with_errno (deployment_dfd, path, TRUE); + if (ret_layout->boot_dfd == -1) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "openat(%s)", path); + } + else + break; + } + + if (ret_layout->boot_dfd == -1) + { + /* No legacy found? We're done */ + *out_layout = NULL; + return TRUE; + } + + /* ret_layout->boot_dfd will point to either /usr/lib/ostree-boot or /boot, let's + * inspect it. + */ + g_auto(GLnxDirFdIterator) dfditer = { 0, }; + if (!glnx_dirfd_iterator_init_at (ret_layout->boot_dfd, ".", FALSE, &dfditer, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent (&dfditer, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + const char *name = dent->d_name; + /* See if this is the kernel */ + if (ret_layout->kernel_srcpath == NULL && g_str_has_prefix (name, "vmlinuz-")) + { + const char *dash = strrchr (name, '-'); + g_assert (dash); + /* In this version, we require that the tree builder generated a + * sha256 of the kernel+initramfs and appended it to the file names. + */ + if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) + { + kernel_checksum = g_strdup (dash + 1); + ret_layout->kernel_srcpath = g_strdup (name); + ret_layout->kernel_namever = g_strndup (name, dash - name); + } + } + /* See if this is the initramfs */ + else if (ret_layout->initramfs_srcpath == NULL && g_str_has_prefix (name, "initramfs-")) + { + const char *dash = strrchr (name, '-'); + g_assert (dash); + if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) + { + initramfs_checksum = g_strdup (dash + 1); + ret_layout->initramfs_srcpath = g_strdup (name); + ret_layout->initramfs_namever = g_strndup (name, dash - name); + } + } + /* See if this is the devicetree */ + else if (ret_layout->devicetree_srcpath == NULL && g_str_has_prefix (name, "devicetree-")) + { + const char *dash = strrchr (name, '-'); + g_assert (dash); + if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) + { + devicetree_checksum = g_strdup (dash + 1); + ret_layout->devicetree_srcpath = g_strdup (name); + ret_layout->devicetree_namever = g_strndup (name, dash - name); + } + } + + /* If we found a kernel, an initramfs and a devicetree, break out of the loop */ + if (ret_layout->kernel_srcpath != NULL && + ret_layout->initramfs_srcpath != NULL && + ret_layout->devicetree_srcpath != NULL) + break; + } + + /* No kernel found? We're done */ + if (ret_layout->kernel_srcpath == NULL) + { + *out_layout = NULL; + return TRUE; + } + + /* The kernel/initramfs checksums must be the same */ + if (ret_layout->initramfs_srcpath != NULL) + { + g_assert (kernel_checksum != NULL); + g_assert (initramfs_checksum != NULL); + if (strcmp (kernel_checksum, initramfs_checksum) != 0) + return glnx_throw (error, "Mismatched kernel checksum vs initrd"); + } + + /* The kernel/devicetree checksums must be the same */ + if (ret_layout->devicetree_srcpath != NULL) + { + g_assert (kernel_checksum != NULL); + g_assert (devicetree_checksum != NULL); + if (strcmp (kernel_checksum, devicetree_checksum) != 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Mismatched kernel checksum vs device tree in tree"); + return FALSE; + } + } + + ret_layout->bootcsum = g_steal_pointer (&kernel_checksum); + + *out_layout = g_steal_pointer (&ret_layout); + return TRUE; +} + +/* Locate kernel/initramfs in the tree; the current standard is to look in + * /usr/lib/modules/$kver/vmlinuz first. + * + * Originally OSTree defined kernels to be found underneath /boot + * in the tree. But that means when mounting /boot at runtime + * we end up masking the content underneath, triggering a warning. + * + * For that reason, and also consistency with the "/usr defines the OS" model we + * later switched to defining the in-tree kernels to be found under + * /usr/lib/ostree-boot. But since then, Fedora at least switched to storing the + * kernel in /usr/lib/modules, which makes sense and isn't ostree-specific, so + * we prefer that now. However, the default Fedora layout doesn't put the + * initramfs there, so we need to look in /usr/lib/ostree-boot first. + */ +static gboolean +get_kernel_from_tree (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeKernelLayout) usrlib_modules_layout = NULL; + g_autoptr(OstreeKernelLayout) legacy_layout = NULL; + + /* First, gather from usr/lib/modules/$kver if it exists */ + if (!get_kernel_from_tree_usrlib_modules (deployment_dfd, &usrlib_modules_layout, cancellable, error)) + return FALSE; + + /* Gather the legacy layout */ + if (!get_kernel_from_tree_legacy_layouts (deployment_dfd, &legacy_layout, cancellable, error)) + return FALSE; + + /* Evaluate the state of both layouts. If there's no legacy layout + * If a legacy layout exists, and it has + * an initramfs but the module layout doesn't, the legacy layout wins. This is + * what happens with rpm-ostree with Fedora today, until rpm-ostree learns the + * new layout. + */ + if (legacy_layout == NULL) + { + /* No legacy layout, let's see if we have a module layout...*/ + if (usrlib_modules_layout == NULL) + { + /* Both layouts are not found? Throw. */ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Failed to find kernel in /usr/lib/modules, /usr/lib/ostree-boot or /boot"); + return FALSE; + } + else + { + /* No legacy, just usr/lib/modules? We're done */ + *out_layout = g_steal_pointer (&usrlib_modules_layout); + return TRUE; + } + } + else if (usrlib_modules_layout != NULL && + usrlib_modules_layout->initramfs_srcpath == NULL && + legacy_layout->initramfs_srcpath != NULL) + { + /* Does the module path not have an initramfs, but the legacy does? Prefer + * the latter then, to make rpm-ostree work as is today. + */ + *out_layout = g_steal_pointer (&legacy_layout); + return TRUE; + } + /* Prefer module layout */ + else if (usrlib_modules_layout != NULL) + { + *out_layout = g_steal_pointer (&usrlib_modules_layout); + return TRUE; + } + else + { + /* And finally fall back to legacy; we know one exists since we + * checked first above. + */ + g_assert (legacy_layout->kernel_srcpath); + *out_layout = g_steal_pointer (&legacy_layout); + return TRUE; + } +} + +/* We used to syncfs(), but that doesn't flush the journal on XFS, + * and since GRUB2 can't read the XFS journal, the system + * could fail to boot. + * + * http://marc.info/?l=linux-fsdevel&m=149520244919284&w=2 + * https://github.com/ostreedev/ostree/pull/1049 + */ +static gboolean +fsfreeze_thaw_cycle (OstreeSysroot *self, + int rootfs_dfd, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("During fsfreeze-thaw", error); + + int sockpair[2]; + if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockpair) < 0) + return glnx_throw_errno_prefix (error, "socketpair"); + glnx_autofd int sock_parent = sockpair[0]; + glnx_autofd int sock_watchdog = sockpair[1]; + + pid_t pid = fork (); + if (pid < 0) + return glnx_throw_errno_prefix (error, "fork"); + + const gboolean debug_fifreeze = (self->debug_flags & OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE)>0; + char c = '!'; + if (pid == 0) /* Child watchdog/unfreezer process. */ + { + glnx_close_fd (&sock_parent); + /* Daemonize, and mask SIGINT/SIGTERM, so we're likely to survive e.g. + * someone doing a `systemctl restart rpm-ostreed` or a Ctrl-C of + * `ostree admin upgrade`. We don't daemonize though if testing so + * that we can waitpid(). + */ + if (!debug_fifreeze) + { + if (daemon (0, 0) < 0) + err (1, "daemon"); + } + int sigs[] = { SIGINT, SIGTERM }; + for (guint i = 0; i < G_N_ELEMENTS (sigs); i++) + { + if (signal (sigs[i], SIG_IGN) == SIG_ERR) + err (1, "signal"); + } + /* Tell the parent we're ready */ + if (write (sock_watchdog, &c, sizeof (c)) != 1) + err (1, "write"); + /* Wait for the parent to say it's going to freeze. */ + ssize_t bytes_read = TEMP_FAILURE_RETRY (read (sock_watchdog, &c, sizeof (c))); + if (bytes_read < 0) + err (1, "read"); + if (bytes_read != 1) + errx (1, "failed to read from parent"); + /* Now we wait for the second message from the parent saying the freeze is + * complete. We have a 30 second timeout; if somehow the parent hasn't + * signaled completion, go ahead and unfreeze. But for debugging, just 1 + * second to avoid exessively lengthining the test suite. + */ + const int timeout_ms = debug_fifreeze ? 1000 : 30000; + struct pollfd pfds[1]; + pfds[0].fd = sock_watchdog; + pfds[0].events = POLLIN | POLLHUP; + int r = TEMP_FAILURE_RETRY (poll (pfds, 1, timeout_ms)); + /* Do a thaw if we hit an error, or if the poll timed out */ + if (r <= 0) + { + /* Ignore errors: + * EINVAL: Not frozen + * EPERM: For running the test suite as non-root + * EOPNOTSUPP: If the filesystem doesn't support it + */ + int saved_errno = errno; + (void) TEMP_FAILURE_RETRY (ioctl (rootfs_dfd, FITHAW, 0)); + errno = saved_errno; + /* But if we got an error from poll, let's log it */ + if (r < 0) + err (1, "poll"); + } + if (debug_fifreeze) + g_printerr ("fifreeze watchdog was run\n"); + /* We use _exit() rather than exit() to avoid tripping over any shared + * libraries in process that aren't fork() safe; for example gjs/spidermonkey: + * https://github.com/ostreedev/ostree/issues/1262 + * This doesn't help for the err()/errx() calls above, but eh... + */ + _exit (EXIT_SUCCESS); + } + else /* Parent process. */ + { + glnx_close_fd (&sock_watchdog); + /* Wait for the watchdog to say it's set up; mainly that it's + * masked SIGTERM successfully. + */ + ssize_t bytes_read = TEMP_FAILURE_RETRY (read (sock_parent, &c, sizeof (c))); + if (bytes_read < 0) + return glnx_throw_errno_prefix (error, "read(watchdog init)"); + if (bytes_read != 1) + return glnx_throw (error, "read(watchdog init)"); + /* And tell the watchdog that we're ready to start */ + if (write (sock_parent, &c, sizeof (c)) != sizeof (c)) + return glnx_throw_errno_prefix (error, "write(watchdog start)"); + /* Testing infrastructure */ + if (debug_fifreeze) + { + int wstatus; + /* Ensure the child has written its data */ + if (TEMP_FAILURE_RETRY (waitpid (pid, &wstatus, 0)) < 0) + return glnx_throw_errno_prefix (error, "waitpid(test-fifreeze)"); + if (!g_spawn_check_exit_status (wstatus, error)) + return glnx_prefix_error (error, "test-fifreeze: "); + return glnx_throw (error, "aborting due to test-fifreeze"); + } + /* Do a freeze/thaw cycle; TODO add a FIFREEZETHAW ioctl */ + if (ioctl (rootfs_dfd, FIFREEZE, 0) != 0) + { + /* Not supported, we're running in the unit tests (as non-root), or + * the filesystem is already frozen (EBUSY). + * OK, let's just do a syncfs. + */ + if (G_IN_SET (errno, EOPNOTSUPP, ENOSYS, EPERM, EBUSY)) + { + /* Warn if the filesystem was already frozen */ + if (errno == EBUSY) + g_debug ("Filesystem already frozen, falling back to syncfs"); + if (TEMP_FAILURE_RETRY (syncfs (rootfs_dfd)) != 0) + return glnx_throw_errno_prefix (error, "syncfs"); + /* Write the completion, and return */ + if (write (sock_parent, &c, sizeof (c)) != sizeof (c)) + return glnx_throw_errno_prefix (error, "write(watchdog syncfs complete)"); + return TRUE; + } + else + return glnx_throw_errno_prefix (error, "ioctl(FIFREEZE)"); + } + /* And finally thaw, then signal our completion to the watchdog */ + if (TEMP_FAILURE_RETRY (ioctl (rootfs_dfd, FITHAW, 0)) != 0) + { + /* Warn but don't error if the filesystem was already thawed */ + if (errno == EINVAL) + g_debug ("Filesystem already thawed"); + else + return glnx_throw_errno_prefix (error, "ioctl(FITHAW)"); + } + if (write (sock_parent, &c, sizeof (c)) != sizeof (c)) + return glnx_throw_errno_prefix (error, "write(watchdog FITHAW complete)"); + } + return TRUE; +} + +typedef struct { + guint64 root_syncfs_msec; + guint64 boot_syncfs_msec; + guint64 extra_syncfs_msec; +} SyncStats; + +/* First, sync the root directory as well as /var and /boot which may + * be separate mount points. Then *in addition*, do a global + * `sync()`. + */ +static gboolean +full_system_sync (OstreeSysroot *self, + SyncStats *out_stats, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Full sync", error); + guint64 start_msec = g_get_monotonic_time () / 1000; + if (syncfs (self->sysroot_fd) != 0) + return glnx_throw_errno_prefix (error, "syncfs(sysroot)"); + guint64 end_msec = g_get_monotonic_time () / 1000; + + out_stats->root_syncfs_msec = (end_msec - start_msec); + + start_msec = g_get_monotonic_time () / 1000; + glnx_autofd int boot_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, "boot", TRUE, &boot_dfd, error)) + return FALSE; + if (!fsfreeze_thaw_cycle (self, boot_dfd, cancellable, error)) + return FALSE; + end_msec = g_get_monotonic_time () / 1000; + out_stats->boot_syncfs_msec = (end_msec - start_msec); + + /* And now out of an excess of conservativism, we still invoke + * sync(). The advantage of still using `syncfs()` above is that we + * actually get error codes out of that API, and we more clearly + * delineate what we actually want to sync in the future when this + * global sync call is removed. + */ + start_msec = g_get_monotonic_time () / 1000; + sync (); + end_msec = g_get_monotonic_time () / 1000; + out_stats->extra_syncfs_msec = (end_msec - start_msec); + + return TRUE; +} + +/* Write out the "bootlinks", which are symlinks pointing to deployments. + * We might be generating a new bootversion (i.e. updating the bootloader config), + * or we might just be generating a "sub-bootversion". + * + * These new links are made active by swap_bootlinks(). + */ +static gboolean +create_new_bootlinks (OstreeSysroot *self, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Creating new current bootlinks", error); + glnx_autofd int ostree_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, "ostree", TRUE, &ostree_dfd, error)) + return FALSE; + + int old_subbootversion; + if (bootversion != self->bootversion) + { + if (!_ostree_sysroot_read_current_subbootversion (self, bootversion, &old_subbootversion, + cancellable, error)) + return FALSE; + } + else + old_subbootversion = self->subbootversion; + + int new_subbootversion = old_subbootversion == 0 ? 1 : 0; + + /* Create the "subbootdir", which is a directory holding a symlink farm pointing to + * deployments per-osname. + */ + g_autofree char *ostree_subbootdir_name = g_strdup_printf ("boot.%d.%d", bootversion, new_subbootversion); + if (!glnx_shutil_rm_rf_at (ostree_dfd, ostree_subbootdir_name, cancellable, error)) + return FALSE; + if (!glnx_shutil_mkdir_p_at (ostree_dfd, ostree_subbootdir_name, 0755, cancellable, error)) + return FALSE; + + glnx_autofd int ostree_subbootdir_dfd = -1; + if (!glnx_opendirat (ostree_dfd, ostree_subbootdir_name, FALSE, &ostree_subbootdir_dfd, error)) + return FALSE; + + for (guint i = 0; i < new_deployments->len; i++) + { + OstreeDeployment *deployment = new_deployments->pdata[i]; + g_autofree char *bootlink_parent = g_strconcat (ostree_deployment_get_osname (deployment), + "/", + ostree_deployment_get_bootcsum (deployment), + NULL); + g_autofree char *bootlink_pathname = g_strdup_printf ("%s/%d", bootlink_parent, ostree_deployment_get_bootserial (deployment)); + g_autofree char *bootlink_target = g_strdup_printf ("../../../deploy/%s/deploy/%s.%d", + ostree_deployment_get_osname (deployment), + ostree_deployment_get_csum (deployment), + ostree_deployment_get_deployserial (deployment)); + + if (!glnx_shutil_mkdir_p_at (ostree_subbootdir_dfd, bootlink_parent, 0755, cancellable, error)) + return FALSE; + + if (!symlink_at_replace (bootlink_target, ostree_subbootdir_dfd, bootlink_pathname, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/* Rename into place symlinks created via create_new_bootlinks(). + */ +static gboolean +swap_bootlinks (OstreeSysroot *self, + int bootversion, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Swapping new version bootlinks", error); + glnx_autofd int ostree_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, "ostree", TRUE, &ostree_dfd, error)) + return FALSE; + + int old_subbootversion; + if (bootversion != self->bootversion) + { + if (!_ostree_sysroot_read_current_subbootversion (self, bootversion, &old_subbootversion, + cancellable, error)) + return FALSE; + } + else + old_subbootversion = self->subbootversion; + + int new_subbootversion = old_subbootversion == 0 ? 1 : 0; + g_autofree char *ostree_bootdir_name = g_strdup_printf ("boot.%d", bootversion); + g_autofree char *ostree_subbootdir_name = g_strdup_printf ("boot.%d.%d", bootversion, new_subbootversion); + if (!symlink_at_replace (ostree_subbootdir_name, ostree_dfd, ostree_bootdir_name, + cancellable, error)) + return FALSE; + + return TRUE; +} + +static GHashTable * +parse_os_release (const char *contents, + const char *split) +{ + g_autofree char **lines = g_strsplit (contents, split, -1); + GHashTable *ret = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + for (char **iter = lines; *iter; iter++) + { + g_autofree char *line = *iter; + + if (g_str_has_prefix (line, "#")) + continue; + + char *eq = strchr (line, '='); + if (!eq) + continue; + + *eq = '\0'; + const char *quotedval = eq + 1; + char *val = g_shell_unquote (quotedval, NULL); + if (!val) + continue; + + g_hash_table_insert (ret, g_steal_pointer (&line), val); + } + + return ret; +} + +/* Given @deployment, prepare it to be booted; basically copying its + * kernel/initramfs into /boot/ostree (if needed) and writing out an entry in + * /boot/loader/entries. + */ +static gboolean +install_deployment_kernel (OstreeSysroot *sysroot, + OstreeRepo *repo, + int new_bootversion, + OstreeDeployment *deployment, + guint n_deployments, + gboolean show_osname, + GCancellable *cancellable, + GError **error) + +{ + GLNX_AUTO_PREFIX_ERROR ("Installing kernel", error); + OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment); + g_autofree char *deployment_dirpath = ostree_sysroot_get_deployment_dirpath (sysroot, deployment); + glnx_autofd int deployment_dfd = -1; + if (!glnx_opendirat (sysroot->sysroot_fd, deployment_dirpath, FALSE, + &deployment_dfd, error)) + return FALSE; + + /* We need to label the kernels */ + g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error); + if (!sepolicy) + return FALSE; + + /* Find the kernel/initramfs/devicetree in the tree */ + g_autoptr(OstreeKernelLayout) kernel_layout = NULL; + if (!get_kernel_from_tree (deployment_dfd, &kernel_layout, + cancellable, error)) + return FALSE; + + glnx_autofd int boot_dfd = -1; + if (!glnx_opendirat (sysroot->sysroot_fd, "boot", TRUE, &boot_dfd, error)) + return FALSE; + + const char *osname = ostree_deployment_get_osname (deployment); + const char *bootcsum = ostree_deployment_get_bootcsum (deployment); + g_assert_cmpstr (kernel_layout->bootcsum, ==, bootcsum); + g_autofree char *bootcsumdir = g_strdup_printf ("ostree/%s-%s", osname, bootcsum); + g_autofree char *bootconfdir = g_strdup_printf ("loader.%d/entries", new_bootversion); + g_autofree char *bootconf_name = g_strdup_printf ("ostree-%d-%s.conf", + n_deployments - ostree_deployment_get_index (deployment), + osname); + if (!glnx_shutil_mkdir_p_at (boot_dfd, bootcsumdir, 0775, cancellable, error)) + return FALSE; + + glnx_autofd int bootcsum_dfd = -1; + if (!glnx_opendirat (boot_dfd, bootcsumdir, TRUE, &bootcsum_dfd, error)) + return FALSE; + + if (!glnx_shutil_mkdir_p_at (boot_dfd, bootconfdir, 0775, cancellable, error)) + return FALSE; + + /* Install (hardlink/copy) the kernel into /boot/ostree/osname-${bootcsum} if + * it doesn't exist already. + */ + struct stat stbuf; + if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->kernel_namever, &stbuf, 0, error)) + return FALSE; + if (errno == ENOENT) + { + if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->kernel_srcpath, + bootcsum_dfd, kernel_layout->kernel_namever, + sysroot->debug_flags, + cancellable, error)) + return FALSE; + } + + /* If we have an initramfs, then install it into + * /boot/ostree/osname-${bootcsum} if it doesn't exist already. + */ + if (kernel_layout->initramfs_srcpath) + { + g_assert (kernel_layout->initramfs_namever); + if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->initramfs_namever, &stbuf, 0, error)) + return FALSE; + if (errno == ENOENT) + { + if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->initramfs_srcpath, + bootcsum_dfd, kernel_layout->initramfs_namever, + sysroot->debug_flags, + cancellable, error)) + return FALSE; + } + } + + if (kernel_layout->devicetree_srcpath) + { + /* If devicetree_namever is set a single device tree is deployed */ + if (kernel_layout->devicetree_namever) + { + if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->devicetree_namever, &stbuf, 0, error)) + return FALSE; + if (errno == ENOENT) + { + if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->devicetree_srcpath, + bootcsum_dfd, kernel_layout->devicetree_namever, + sysroot->debug_flags, + cancellable, error)) + return FALSE; + } + } + else + { + if (!copy_dir_recurse(kernel_layout->boot_dfd, bootcsum_dfd, kernel_layout->devicetree_srcpath, + sysroot->debug_flags, cancellable, error)) + return FALSE; + } + } + + if (kernel_layout->kernel_hmac_srcpath) + { + if (!glnx_fstatat_allow_noent (bootcsum_dfd, kernel_layout->kernel_hmac_namever, &stbuf, 0, error)) + return FALSE; + if (errno == ENOENT) + { + if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->kernel_hmac_srcpath, + bootcsum_dfd, kernel_layout->kernel_hmac_namever, + sysroot->debug_flags, + cancellable, error)) + return FALSE; + } + } + + g_autofree char *contents = NULL; + if (!glnx_fstatat_allow_noent (deployment_dfd, "usr/lib/os-release", &stbuf, 0, error)) + return FALSE; + if (errno == ENOENT) + { + contents = glnx_file_get_contents_utf8_at (deployment_dfd, "etc/os-release", NULL, + cancellable, error); + if (!contents) + return glnx_prefix_error (error, "Reading /etc/os-release"); + } + else + { + contents = glnx_file_get_contents_utf8_at (deployment_dfd, "usr/lib/os-release", NULL, + cancellable, error); + if (!contents) + return glnx_prefix_error (error, "Reading /usr/lib/os-release"); + } + + g_autoptr(GHashTable) osrelease_values = parse_os_release (contents, "\n"); + /* title */ + const char *val = g_hash_table_lookup (osrelease_values, "PRETTY_NAME"); + if (val == NULL) + val = g_hash_table_lookup (osrelease_values, "ID"); + if (val == NULL) + return glnx_throw (error, "No PRETTY_NAME or ID in /etc/os-release"); + + g_autofree char *deployment_version = NULL; + if (repo) + { + /* Try extracting a version for this deployment. */ + const char *csum = ostree_deployment_get_csum (deployment); + g_autoptr(GVariant) variant = NULL; + g_autoptr(GVariant) metadata = NULL; + + /* XXX Copying ot_admin_checksum_version() + bits from + * ot-admin-builtin-status.c. Maybe this should be + * public API in libostree? */ + if (ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, csum, + &variant, NULL)) + { + metadata = g_variant_get_child_value (variant, 0); + g_variant_lookup (metadata, OSTREE_COMMIT_META_KEY_VERSION, "s", &deployment_version); + } + } + + /* XXX The SYSLINUX bootloader backend actually parses the title string + * (specifically, it looks for the substring "(ostree"), so further + * changes to the title format may require updating that backend. */ + g_autoptr(GString) title_key = g_string_new (val); + if (deployment_version && *deployment_version && !strstr (val, deployment_version)) + { + g_string_append_c (title_key, ' '); + g_string_append (title_key, deployment_version); + } + g_string_append (title_key, " (ostree"); + if (show_osname) + { + g_string_append_c (title_key, ':'); + g_string_append (title_key, osname); + } + + g_string_append_printf (title_key, ":%d", ostree_deployment_get_index (deployment)); + + g_string_append_c (title_key, ')'); + ostree_bootconfig_parser_set (bootconfig, "title", title_key->str); + + g_autofree char *version_key = g_strdup_printf ("%d", n_deployments - ostree_deployment_get_index (deployment)); + ostree_bootconfig_parser_set (bootconfig, OSTREE_COMMIT_META_KEY_VERSION, version_key); + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->kernel_namever, NULL); + ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath); + + val = ostree_bootconfig_parser_get (bootconfig, "options"); + g_autoptr(OstreeKernelArgs) kargs = ostree_kernel_args_from_string (val); + + if (kernel_layout->initramfs_namever) + { + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL); + ostree_bootconfig_parser_set (bootconfig, "initrd", boot_relpath); + } + else + { + g_autofree char *prepare_root_arg = NULL; + prepare_root_arg = g_strdup_printf ("init=/ostree/boot.%d/%s/%s/%d/usr/lib/ostree/ostree-prepare-root", + new_bootversion, osname, bootcsum, + ostree_deployment_get_bootserial (deployment)); + ostree_kernel_args_replace_take (kargs, g_steal_pointer (&prepare_root_arg)); + } + + if (kernel_layout->devicetree_namever) + { + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_namever, NULL); + ostree_bootconfig_parser_set (bootconfig, "devicetree", boot_relpath); + } + else if (kernel_layout->devicetree_srcpath) + { + /* If devicetree_srcpath is set but devicetree_namever is NULL, then we + * want to point to a whole directory of device trees. + * See: https://github.com/ostreedev/ostree/issues/1900 + */ + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_srcpath, NULL); + ostree_bootconfig_parser_set (bootconfig, "fdtdir", boot_relpath); + } + + /* Note this is parsed in ostree-impl-system-generator.c */ + g_autofree char *ostree_kernel_arg = g_strdup_printf ("ostree=/ostree/boot.%d/%s/%s/%d", + new_bootversion, osname, bootcsum, + ostree_deployment_get_bootserial (deployment)); + ostree_kernel_args_replace_take (kargs, g_steal_pointer (&ostree_kernel_arg)); + + g_autofree char *options_key = ostree_kernel_args_to_string (kargs); + ostree_bootconfig_parser_set (bootconfig, "options", options_key); + + glnx_autofd int bootconf_dfd = -1; + if (!glnx_opendirat (boot_dfd, bootconfdir, TRUE, &bootconf_dfd, error)) + return FALSE; + + if (!ostree_bootconfig_parser_write_at (ostree_deployment_get_bootconfig (deployment), + bootconf_dfd, bootconf_name, + cancellable, error)) + return FALSE; + + return TRUE; +} + +/* We generate the symlink on disk, then potentially do a syncfs() to ensure + * that it (and everything else we wrote) has hit disk. Only after that do we + * rename it into place. + */ +static gboolean +prepare_new_bootloader_link (OstreeSysroot *sysroot, + int current_bootversion, + int new_bootversion, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Preparing final bootloader swap", error); + g_assert ((current_bootversion == 0 && new_bootversion == 1) || + (current_bootversion == 1 && new_bootversion == 0)); + + g_autofree char *new_target = g_strdup_printf ("loader.%d", new_bootversion); + + /* We shouldn't actually need to replace but it's easier to reuse + that code */ + if (!symlink_at_replace (new_target, sysroot->sysroot_fd, "boot/loader.tmp", + cancellable, error)) + return FALSE; + + return TRUE; +} + +/* Update the /boot/loader symlink to point to /boot/loader.$new_bootversion */ +static gboolean +swap_bootloader (OstreeSysroot *sysroot, + OstreeBootloader *bootloader, + int current_bootversion, + int new_bootversion, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Final bootloader swap", error); + + g_assert ((current_bootversion == 0 && new_bootversion == 1) || + (current_bootversion == 1 && new_bootversion == 0)); + + glnx_autofd int boot_dfd = -1; + if (!glnx_opendirat (sysroot->sysroot_fd, "boot", TRUE, &boot_dfd, error)) + return FALSE; + + /* The symlink was already written, and we used syncfs() to ensure + * its data is in place. Renaming now should give us atomic semantics; + * see https://bugzilla.gnome.org/show_bug.cgi?id=755595 + */ + if (!glnx_renameat (boot_dfd, "loader.tmp", boot_dfd, "loader", error)) + return FALSE; + + /* Now we explicitly fsync this directory, even though it + * isn't required for atomicity, for two reasons: + * - It should be very cheap as we're just syncing whatever + * data was written since the last sync which was hopefully + * less than a second ago. + * - It should be sync'd before shutdown as that could crash + * for whatever reason, and we wouldn't want to confuse the + * admin by going back to the previous session. + */ + if (fsync (boot_dfd) != 0) + return glnx_throw_errno_prefix (error, "fsync(boot)"); + + /* TODO: In the future also execute this automatically via a systemd unit + * if we detect it's necessary. + **/ + if (bootloader) + { + if (!_ostree_bootloader_post_bls_sync (bootloader, cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/* Deployments may share boot checksums; the bootserial indexes them + * per-bootchecksum. It's used by the symbolic links after the bootloader. + */ +static void +assign_bootserials (GPtrArray *deployments) +{ + g_autoptr(GHashTable) serials = + g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + + for (guint i = 0; i < deployments->len; i++) + { + OstreeDeployment *deployment = deployments->pdata[i]; + const char *bootcsum = ostree_deployment_get_bootcsum (deployment); + /* Note that not-found maps to NULL which converts to zero */ + guint count = GPOINTER_TO_UINT (g_hash_table_lookup (serials, bootcsum)); + g_hash_table_replace (serials, (char*) bootcsum, + GUINT_TO_POINTER (count + 1)); + + ostree_deployment_set_bootserial (deployment, count); + } +} + +static char* +get_deployment_nonostree_kargs (OstreeDeployment *deployment) +{ + /* pick up kernel arguments but filter out ostree= */ + OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment); + const char *boot_options = ostree_bootconfig_parser_get (bootconfig, "options"); + g_autoptr(OstreeKernelArgs) kargs = ostree_kernel_args_from_string (boot_options); + ostree_kernel_args_replace (kargs, "ostree"); + return ostree_kernel_args_to_string (kargs); +} + +static char* +get_deployment_ostree_version (OstreeRepo *repo, + OstreeDeployment *deployment) +{ + const char *csum = ostree_deployment_get_csum (deployment); + + g_autofree char *version = NULL; + g_autoptr(GVariant) variant = NULL; + if (ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, csum, &variant, NULL)) + { + g_autoptr(GVariant) metadata = g_variant_get_child_value (variant, 0); + g_variant_lookup (metadata, OSTREE_COMMIT_META_KEY_VERSION, "s", &version); + } + + return g_steal_pointer (&version); +} + +/* OSTree implements a special optimization where we want to avoid touching + * the bootloader configuration if the kernel layout hasn't changed. This is + * handled by the ostree= kernel argument referring to a "bootlink". But + * we *do* need to update the bootloader configuration if the kernel arguments + * change. + * + * Hence, this function determines if @a and @b are fully compatible from a + * bootloader perspective. + */ +static gboolean +deployment_bootconfigs_equal (OstreeRepo *repo, + OstreeDeployment *a, + OstreeDeployment *b) +{ + /* same kernel & initramfs? */ + const char *a_bootcsum = ostree_deployment_get_bootcsum (a); + const char *b_bootcsum = ostree_deployment_get_bootcsum (b); + if (strcmp (a_bootcsum, b_bootcsum) != 0) + return FALSE; + + /* same kargs? */ + g_autofree char *a_boot_options_without_ostree = get_deployment_nonostree_kargs (a); + g_autofree char *b_boot_options_without_ostree = get_deployment_nonostree_kargs (b); + if (strcmp (a_boot_options_without_ostree, b_boot_options_without_ostree) != 0) + return FALSE; + + /* same ostree version? this is just for the menutitle, we won't have to cp the kernel */ + g_autofree char *a_version = get_deployment_ostree_version (repo, a); + g_autofree char *b_version = get_deployment_ostree_version (repo, b); + if (g_strcmp0 (a_version, b_version) != 0) + return FALSE; + + return TRUE; +} + +/* This used to be a temporary hack to create "current" symbolic link + * that's easy to follow inside the gnome-ostree build scripts (now + * gnome-continuous). It wasn't atomic, and nowadays people can use + * the OSTree API to find deployments. + */ +static gboolean +cleanup_legacy_current_symlinks (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GString) buf = g_string_new (""); + + for (guint i = 0; i < self->deployments->len; i++) + { + OstreeDeployment *deployment = self->deployments->pdata[i]; + const char *osname = ostree_deployment_get_osname (deployment); + + g_string_truncate (buf, 0); + g_string_append_printf (buf, "ostree/deploy/%s/current", osname); + + if (!ot_ensure_unlinked_at (self->sysroot_fd, buf->str, error)) + return FALSE; + } + + return TRUE; +} + +/* Detect whether or not @path refers to a read-only mountpoint. This is + * currently just used to handle a potentially read-only /boot by transiently + * remounting it read-write. In the future we might also do this for e.g. + * /sysroot. + */ +static gboolean +is_ro_mount (const char *path) +{ +#ifdef HAVE_LIBMOUNT + /* Dragging in all of this crud is apparently necessary just to determine + * whether something is a mount point. + * + * Systemd has a totally different implementation in + * src/basic/mount-util.c. + */ + struct libmnt_table *tb = mnt_new_table_from_file ("/proc/self/mountinfo"); + struct libmnt_fs *fs; + struct libmnt_cache *cache; + gboolean is_mount = FALSE; + struct statvfs stvfsbuf; + + if (!tb) + return FALSE; + + /* to canonicalize all necessary paths */ + cache = mnt_new_cache (); + mnt_table_set_cache (tb, cache); + + fs = mnt_table_find_target(tb, path, MNT_ITER_BACKWARD); + is_mount = fs && mnt_fs_get_target (fs); +#ifdef HAVE_MNT_UNREF_CACHE + mnt_unref_table (tb); + mnt_unref_cache (cache); +#else + mnt_free_table (tb); + mnt_free_cache (cache); +#endif + + if (!is_mount) + return FALSE; + + /* We *could* parse the options, but it seems more reliable to + * introspect the actual mount at runtime. + */ + if (statvfs (path, &stvfsbuf) == 0) + return (stvfsbuf.f_flag & ST_RDONLY) != 0; + +#endif + return FALSE; +} + +/** + * ostree_sysroot_write_deployments: + * @self: Sysroot + * @new_deployments: (element-type OstreeDeployment): List of new deployments + * @cancellable: Cancellable + * @error: Error + * + * Older version of ostree_sysroot_write_deployments_with_options(). This + * version will perform post-deployment cleanup by default. + */ +gboolean +ostree_sysroot_write_deployments (OstreeSysroot *self, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error) +{ + OstreeSysrootWriteDeploymentsOpts opts = { .do_postclean = TRUE }; + return ostree_sysroot_write_deployments_with_options (self, new_deployments, &opts, + cancellable, error); +} + +/* Handle writing out a new bootloader config. One reason this needs to be a + * helper function is to handle wrapping it with temporarily remounting /boot + * rw. + */ +static gboolean +write_deployments_bootswap (OstreeSysroot *self, + GPtrArray *new_deployments, + OstreeSysrootWriteDeploymentsOpts *opts, + OstreeBootloader *bootloader, + SyncStats *out_syncstats, + GCancellable *cancellable, + GError **error) +{ + const int new_bootversion = self->bootversion ? 0 : 1; + + g_autofree char* new_loader_entries_dir = g_strdup_printf ("boot/loader.%d/entries", new_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, new_loader_entries_dir, cancellable, error)) + return FALSE; + if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, new_loader_entries_dir, 0755, + cancellable, error)) + return FALSE; + + /* Need the repo to try and extract the versions for deployments. + * But this is a "nice-to-have" for the bootloader UI, so failure + * here is not fatal to the whole operation. We just gracefully + * fall back to the deployment index. */ + g_autoptr(OstreeRepo) repo = NULL; + (void) ostree_sysroot_get_repo (self, &repo, cancellable, NULL); + + /* Only show the osname in bootloader titles if there are multiple + * osname's among the new deployments. Check for that here. */ + gboolean show_osname = FALSE; + for (guint i = 1; i < new_deployments->len; i++) + { + const char *osname_0 = ostree_deployment_get_osname (new_deployments->pdata[0]); + const char *osname_i = ostree_deployment_get_osname (new_deployments->pdata[i]); + if (!g_str_equal (osname_0, osname_i)) + { + show_osname = TRUE; + break; + } + } + + for (guint i = 0; i < new_deployments->len; i++) + { + OstreeDeployment *deployment = new_deployments->pdata[i]; + if (!install_deployment_kernel (self, repo, new_bootversion, + deployment, new_deployments->len, + show_osname, cancellable, error)) + return FALSE; + } + + /* Create and swap bootlinks for *new* version */ + if (!create_new_bootlinks (self, new_bootversion, + new_deployments, + cancellable, error)) + return FALSE; + if (!swap_bootlinks (self, new_bootversion, new_deployments, + cancellable, error)) + return FALSE; + + g_debug ("Using bootloader: %s", bootloader ? + g_type_name (G_TYPE_FROM_INSTANCE (bootloader)) : "(none)"); + + if (bootloader) + { + if (!_ostree_bootloader_write_config (bootloader, new_bootversion, + new_deployments, cancellable, + error)) + return glnx_prefix_error (error, "Bootloader write config"); + } + + if (!prepare_new_bootloader_link (self, self->bootversion, new_bootversion, + cancellable, error)) + return FALSE; + + if (!full_system_sync (self, out_syncstats, cancellable, error)) + return FALSE; + + if (!swap_bootloader (self, bootloader, self->bootversion, new_bootversion, + cancellable, error)) + return FALSE; + + return TRUE; +} + +/* Actions taken after writing deployments is complete */ +static gboolean +write_deployments_finish (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + if (!_ostree_sysroot_bump_mtime (self, error)) + return FALSE; + + /* Now reload from disk */ + if (!ostree_sysroot_load (self, cancellable, error)) + return glnx_prefix_error (error, "Reloading deployments after commit"); + + if (!cleanup_legacy_current_symlinks (self, cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_write_deployments_with_options: + * @self: Sysroot + * @new_deployments: (element-type OstreeDeployment): List of new deployments + * @opts: Options + * @cancellable: Cancellable + * @error: Error + * + * Assuming @new_deployments have already been deployed in place on disk via + * ostree_sysroot_deploy_tree(), atomically update bootloader configuration. By + * default, no post-transaction cleanup will be performed. You should invoke + * ostree_sysroot_cleanup() at some point after the transaction, or specify + * `do_postclean` in @opts. Skipping the post-transaction cleanup is useful + * if for example you want to control pruning of the repository. + * + * Since: 2017.4 + */ +gboolean +ostree_sysroot_write_deployments_with_options (OstreeSysroot *self, + GPtrArray *new_deployments, + OstreeSysrootWriteDeploymentsOpts *opts, + GCancellable *cancellable, + GError **error) +{ + g_assert (self->loadstate == OSTREE_SYSROOT_LOAD_STATE_LOADED); + + if (!_ostree_sysroot_ensure_writable (self, error)) + return FALSE; + + /* Dealing with the staged deployment is quite tricky here. This function is + * primarily concerned with writing out "finalized" deployments which have + * bootloader entries. Originally, we simply dropped the staged deployment + * here unconditionally. Now, the high level strategy is to retain it, but + * *only* if it's the first item in the new deployment list - otherwise, it's + * silently dropped. + */ + + g_autoptr(GPtrArray) new_deployments_copy = g_ptr_array_new (); + gboolean removed_staged = (self->staged_deployment != NULL); + if (new_deployments->len > 0) + { + OstreeDeployment *first = new_deployments->pdata[0]; + /* If the first deployment is the staged, we filter it out for now */ + g_assert (first); + if (first == self->staged_deployment) + { + g_assert (ostree_deployment_is_staged (first)); + + /* In this case note staged was retained */ + removed_staged = FALSE; + } + + /* Create a copy without any staged deployments */ + for (guint i = 0; i < new_deployments->len; i++) + { + OstreeDeployment *deployment = new_deployments->pdata[i]; + if (!ostree_deployment_is_staged (deployment)) + g_ptr_array_add (new_deployments_copy, deployment); + } + new_deployments = new_deployments_copy; + } + + /* Take care of removing the staged deployment's on-disk state if we should */ + if (removed_staged) + { + g_assert (self->staged_deployment); + g_assert (self->staged_deployment == self->deployments->pdata[0]); + + if (!glnx_unlinkat (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, 0, error)) + return FALSE; + + if (!_ostree_sysroot_rmrf_deployment (self, self->staged_deployment, cancellable, error)) + return FALSE; + + /* Clear it out of the *current* deployments list to maintain invariants */ + self->staged_deployment = NULL; + g_ptr_array_remove_index (self->deployments, 0); + } + const guint nonstaged_current_len = self->deployments->len - (self->staged_deployment ? 1 : 0); + + /* Assign a bootserial to each new deployment. + */ + assign_bootserials (new_deployments); + + /* Determine whether or not we need to touch the bootloader + * configuration. If we have an equal number of deployments with + * matching bootloader configuration, then we can just swap the + * subbootversion bootlinks. + */ + gboolean requires_new_bootversion = FALSE; + + if (new_deployments->len != nonstaged_current_len) + requires_new_bootversion = TRUE; + else + { + gboolean is_noop = TRUE; + OstreeRepo *repo = ostree_sysroot_repo (self); + for (guint i = 0; i < new_deployments->len; i++) + { + OstreeDeployment *cur_deploy = self->deployments->pdata[i]; + if (ostree_deployment_is_staged (cur_deploy)) + continue; + OstreeDeployment *new_deploy = new_deployments->pdata[i]; + if (!deployment_bootconfigs_equal (repo, cur_deploy, new_deploy)) + { + requires_new_bootversion = TRUE; + is_noop = FALSE; + break; + } + if (cur_deploy != new_deploy) + is_noop = FALSE; + } + + /* If we're passed the same set of deployments, we don't need + * to drop into the rest of this function which deals with + * changing the bootloader config. + */ + if (is_noop) + { + g_assert (!requires_new_bootversion); + /* However, if we dropped the staged deployment, we still + * need to do finalization steps such as regenerating + * the refs and bumping the mtime. + */ + if (removed_staged) + { + if (!write_deployments_finish (self, cancellable, error)) + return FALSE; + } + return TRUE; + } + } + + gboolean found_booted_deployment = FALSE; + for (guint i = 0; i < new_deployments->len; i++) + { + OstreeDeployment *deployment = new_deployments->pdata[i]; + g_assert (!ostree_deployment_is_staged (deployment)); + + if (deployment == self->booted_deployment) + found_booted_deployment = TRUE; + + g_autoptr(GFile) deployment_root = ostree_sysroot_get_deployment_directory (self, deployment); + if (!g_file_query_exists (deployment_root, NULL)) + return glnx_throw (error, "Unable to find expected deployment root: %s", + gs_file_get_path_cached (deployment_root)); + + ostree_deployment_set_index (deployment, i); + } + + if (self->booted_deployment && !found_booted_deployment) + return glnx_throw (error, "Attempting to remove booted deployment"); + + gboolean bootloader_is_atomic = FALSE; + SyncStats syncstats = { 0, }; + g_autoptr(OstreeBootloader) bootloader = NULL; + const char *bootloader_config = NULL; + if (!requires_new_bootversion) + { + if (!create_new_bootlinks (self, self->bootversion, + new_deployments, + cancellable, error)) + return FALSE; + + if (!full_system_sync (self, &syncstats, cancellable, error)) + return FALSE; + + if (!swap_bootlinks (self, self->bootversion, + new_deployments, + cancellable, error)) + return FALSE; + + bootloader_is_atomic = TRUE; + } + else + { + gboolean boot_was_ro_mount = FALSE; + if (self->booted_deployment) + boot_was_ro_mount = is_ro_mount ("/boot"); + + g_debug ("boot is ro: %s", boot_was_ro_mount ? "yes" : "no"); + + if (boot_was_ro_mount) + { + if (mount ("/boot", "/boot", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) + return glnx_throw_errno_prefix (error, "Remounting /boot read-write"); + } + + OstreeRepo *repo = ostree_sysroot_repo (self); + + bootloader_config = ostree_repo_get_bootloader (repo); + + g_debug ("Using bootloader configuration: %s", bootloader_config); + + if (g_str_equal (bootloader_config, "auto")) + { + if (!_ostree_sysroot_query_bootloader (self, &bootloader, cancellable, error)) + return FALSE; + } + else if (g_str_equal (bootloader_config, "none")) + { + /* No bootloader specified; do not query bootloaders to run. */ + } + else if (g_str_equal (bootloader_config, "zipl")) + { + /* Because we do not mark zipl as active by default, lets creating one here, + * which is basically the same what _ostree_sysroot_query_bootloader() does + * for other bootloaders if being activated. + * */ + bootloader = (OstreeBootloader*) _ostree_bootloader_zipl_new (self); + } + + bootloader_is_atomic = bootloader != NULL && _ostree_bootloader_is_atomic (bootloader); + + /* Note equivalent of try/finally here */ + gboolean success = write_deployments_bootswap (self, new_deployments, opts, bootloader, + &syncstats, cancellable, error); + /* Below here don't set GError until the if (!success) check. + * Note we only bother remounting if a mount namespace isn't in use. + * */ + if (boot_was_ro_mount && !self->mount_namespace_in_use) + { + if (mount ("/boot", "/boot", NULL, MS_REMOUNT | MS_RDONLY | MS_SILENT, NULL) < 0) + { + /* Only make this a warning because we don't want to + * completely bomb out if some other process happened to + * jump in and open a file there. See above TODO + * around doing this in a new mount namespace. + */ + g_printerr ("warning: Failed to remount /boot read-only: %s\n", strerror (errno)); + } + } + if (!success) + return FALSE; + } + + { g_autofree char *msg = + g_strdup_printf ("%s; bootconfig swap: %s; deployment count change: %i", + (bootloader_is_atomic ? "Transaction complete" : "Bootloader updated"), + requires_new_bootversion ? "yes" : "no", + new_deployments->len - self->deployments->len); + ot_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_DEPLOYMENT_COMPLETE_ID), + "MESSAGE=%s", msg, + "OSTREE_BOOTLOADER=%s", bootloader ? _ostree_bootloader_get_name (bootloader) : "none", + "OSTREE_BOOTLOADER_CONFIG=%s", bootloader_config, + "OSTREE_BOOTLOADER_ATOMIC=%s", bootloader_is_atomic ? "yes" : "no", + "OSTREE_DID_BOOTSWAP=%s", requires_new_bootversion ? "yes" : "no", + "OSTREE_N_DEPLOYMENTS=%u", new_deployments->len, + "OSTREE_SYNCFS_ROOT_MSEC=%" G_GUINT64_FORMAT, syncstats.root_syncfs_msec, + "OSTREE_SYNCFS_BOOT_MSEC=%" G_GUINT64_FORMAT, syncstats.boot_syncfs_msec, + "OSTREE_SYNCFS_EXTRA_MSEC=%" G_GUINT64_FORMAT, syncstats.extra_syncfs_msec, + NULL); + _ostree_sysroot_emit_journal_msg (self, msg); + } + + if (!write_deployments_finish (self, cancellable, error)) + return FALSE; + + /* And finally, cleanup of any leftover data. + */ + if (opts->do_postclean) + { + if (!ostree_sysroot_cleanup (self, cancellable, error)) + return glnx_prefix_error (error, "Performing final cleanup"); + } + + return TRUE; +} + +static gboolean +allocate_deployserial (OstreeSysroot *self, + const char *osname, + const char *revision, + int *out_deployserial, + GCancellable *cancellable, + GError **error) +{ + int new_deployserial = 0; + g_autoptr(GPtrArray) tmp_current_deployments = + g_ptr_array_new_with_free_func (g_object_unref); + + glnx_autofd int deploy_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, "ostree/deploy", TRUE, &deploy_dfd, error)) + return FALSE; + + if (!_ostree_sysroot_list_deployment_dirs_for_os (deploy_dfd, osname, + tmp_current_deployments, + cancellable, error)) + return FALSE; + + for (guint i = 0; i < tmp_current_deployments->len; i++) + { + OstreeDeployment *deployment = tmp_current_deployments->pdata[i]; + + if (strcmp (ostree_deployment_get_csum (deployment), revision) != 0) + continue; + + new_deployserial = MAX(new_deployserial, ostree_deployment_get_deployserial (deployment)+1); + } + + *out_deployserial = new_deployserial; + return TRUE; +} + +void +_ostree_deployment_set_bootconfig_from_kargs (OstreeDeployment *deployment, + char **override_kernel_argv) +{ + /* Create an empty boot configuration; we will merge things into + * it as we go. + */ + g_autoptr(OstreeBootconfigParser) bootconfig = ostree_bootconfig_parser_new (); + ostree_deployment_set_bootconfig (deployment, bootconfig); + + /* After this, install_deployment_kernel() will set the other boot + * options and write it out to disk. + */ + if (override_kernel_argv) + { + g_autoptr(OstreeKernelArgs) kargs = ostree_kernel_args_new (); + ostree_kernel_args_append_argv (kargs, override_kernel_argv); + g_autofree char *new_options = ostree_kernel_args_to_string (kargs); + ostree_bootconfig_parser_set (bootconfig, "options", new_options); + } +} + +/* The first part of writing a deployment. This primarily means doing the + * hardlink farm checkout, but we also compute some initial state. + */ +static gboolean +sysroot_initialize_deployment (OstreeSysroot *self, + const char *osname, + const char *revision, + GKeyFile *origin, + char **override_kernel_argv, + OstreeDeployment **out_new_deployment, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (osname != NULL || self->booted_deployment != NULL, FALSE); + + if (osname == NULL) + osname = ostree_deployment_get_osname (self->booted_deployment); + + OstreeRepo *repo = ostree_sysroot_repo (self); + + gint new_deployserial; + if (!allocate_deployserial (self, osname, revision, &new_deployserial, + cancellable, error)) + return FALSE; + + g_autofree char *new_bootcsum = NULL; + g_autoptr(OstreeDeployment) new_deployment = + ostree_deployment_new (0, osname, revision, new_deployserial, + new_bootcsum, -1); + ostree_deployment_set_origin (new_deployment, origin); + + /* Check out the userspace tree onto the filesystem */ + glnx_autofd int deployment_dfd = -1; + if (!checkout_deployment_tree (self, repo, new_deployment, &deployment_dfd, + cancellable, error)) + return FALSE; + + g_autoptr(OstreeKernelLayout) kernel_layout = NULL; + if (!get_kernel_from_tree (deployment_dfd, &kernel_layout, + cancellable, error)) + return FALSE; + + _ostree_deployment_set_bootcsum (new_deployment, kernel_layout->bootcsum); + _ostree_deployment_set_bootconfig_from_kargs (new_deployment, override_kernel_argv); + + if (!prepare_deployment_etc (self, repo, new_deployment, deployment_dfd, + cancellable, error)) + return FALSE; + + ot_transfer_out_value (out_new_deployment, &new_deployment); + return TRUE; +} + +/* Get a directory fd for the /var of @deployment. + * Before we supported having /var be a separate mount point, + * this was easy. However, as https://github.com/ostreedev/ostree/issues/1729 + * raised, in the primary case where we're + * doing a new deployment for the booted stateroot, + * we need to use /var/. This code doesn't correctly + * handle the case of `ostree admin --sysroot upgrade`, + * nor (relatedly) the case of upgrading a separate stateroot. + */ +static gboolean +get_var_dfd (OstreeSysroot *self, + int osdeploy_dfd, + OstreeDeployment *deployment, + int *ret_fd, + GError **error) +{ + const char *booted_stateroot = + self->booted_deployment ? ostree_deployment_get_osname (self->booted_deployment) : NULL; + + int base_dfd; + const char *base_path; + /* The common case is when we're doing a new deployment for the same stateroot (osname). + * If we have a separate mounted /var, then we need to use it - the /var in the + * stateroot will probably just be an empty directory. + * + * If the stateroot doesn't match, just fall back to /var in the target's stateroot. + */ + if (g_strcmp0 (booted_stateroot, ostree_deployment_get_osname (deployment)) == 0) + { + base_dfd = AT_FDCWD; + base_path = "/var"; + } + else + { + base_dfd = osdeploy_dfd; + base_path = "var"; + } + + return glnx_opendirat (base_dfd, base_path, TRUE, ret_fd, error); +} + +static gboolean +sysroot_finalize_deployment (OstreeSysroot *self, + OstreeDeployment *deployment, + char **override_kernel_argv, + OstreeDeployment *merge_deployment, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); + glnx_autofd int deployment_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error)) + return FALSE; + + /* Only use the merge if we didn't get an override */ + if (!override_kernel_argv && merge_deployment) + { + /* Override the bootloader arguments */ + OstreeBootconfigParser *merge_bootconfig = ostree_deployment_get_bootconfig (merge_deployment); + if (merge_bootconfig) + { + const char *opts = ostree_bootconfig_parser_get (merge_bootconfig, "options"); + ostree_bootconfig_parser_set (ostree_deployment_get_bootconfig (deployment), "options", opts); + } + + } + + if (merge_deployment) + { + /* And do the /etc merge */ + if (!merge_configuration_from (self, merge_deployment, deployment, deployment_dfd, + cancellable, error)) + return FALSE; + } + + const char *osdeploypath = glnx_strjoina ("ostree/deploy/", ostree_deployment_get_osname (deployment)); + glnx_autofd int os_deploy_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, osdeploypath, TRUE, &os_deploy_dfd, error)) + return FALSE; + glnx_autofd int var_dfd = -1; + if (!get_var_dfd (self, os_deploy_dfd, deployment, &var_dfd, error)) + return FALSE; + + /* Ensure that the new deployment does not have /etc/.updated or + * /var/.updated so that systemd ConditionNeedsUpdate=/etc|/var services run + * after rebooting. + */ + if (!ot_ensure_unlinked_at (deployment_dfd, "etc/.updated", error)) + return FALSE; + if (!ot_ensure_unlinked_at (var_dfd, ".updated", error)) + return FALSE; + + g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error); + if (!sepolicy) + return FALSE; + + if (!selinux_relabel_var_if_needed (self, sepolicy, os_deploy_dfd, cancellable, error)) + return FALSE; + + /* Rewrite the origin using the final merged selinux config, just to be + * conservative about getting the right labels. + */ + if (!write_origin_file_internal (self, sepolicy, deployment, + ostree_deployment_get_origin (deployment), + GLNX_FILE_REPLACE_NODATASYNC, + cancellable, error)) + return FALSE; + + /* Seal it */ + if (!(self->debug_flags & OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS)) + { + if (!ostree_sysroot_deployment_set_mutable (self, deployment, FALSE, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_sysroot_deploy_tree: + * @self: Sysroot + * @osname: (allow-none): osname to use for merge deployment + * @revision: Checksum to add + * @origin: (allow-none): Origin to use for upgrades + * @provided_merge_deployment: (allow-none): Use this deployment for merge path + * @override_kernel_argv: (allow-none) (array zero-terminated=1) (element-type utf8): Use these as kernel arguments; if %NULL, inherit options from provided_merge_deployment + * @out_new_deployment: (out): The new deployment path + * @cancellable: Cancellable + * @error: Error + * + * Check out deployment tree with revision @revision, performing a 3 + * way merge with @provided_merge_deployment for configuration. + * + * While this API is not deprecated, you most likely want to use the + * ostree_sysroot_stage_tree() API. + */ +gboolean +ostree_sysroot_deploy_tree (OstreeSysroot *self, + const char *osname, + const char *revision, + GKeyFile *origin, + OstreeDeployment *provided_merge_deployment, + char **override_kernel_argv, + OstreeDeployment **out_new_deployment, + GCancellable *cancellable, + GError **error) +{ + if (!_ostree_sysroot_ensure_writable (self, error)) + return FALSE; + + g_autoptr(OstreeDeployment) deployment = NULL; + if (!sysroot_initialize_deployment (self, osname, revision, origin, override_kernel_argv, + &deployment, cancellable, error)) + return FALSE; + + if (!sysroot_finalize_deployment (self, deployment, override_kernel_argv, + provided_merge_deployment, + cancellable, error)) + return FALSE; + + *out_new_deployment = g_steal_pointer (&deployment); + return TRUE; +} + +/* Serialize information about a deployment to a variant, used by the staging + * code. + */ +static GVariant * +serialize_deployment_to_variant (OstreeDeployment *deployment) +{ + g_auto(GVariantBuilder) builder = OT_VARIANT_BUILDER_INITIALIZER; + g_variant_builder_init (&builder, (GVariantType*)"a{sv}"); + g_autofree char *name = + g_strdup_printf ("%s.%d", ostree_deployment_get_csum (deployment), + ostree_deployment_get_deployserial (deployment)); + g_variant_builder_add (&builder, "{sv}", "name", + g_variant_new_string (name)); + g_variant_builder_add (&builder, "{sv}", "osname", + g_variant_new_string (ostree_deployment_get_osname (deployment))); + g_variant_builder_add (&builder, "{sv}", "bootcsum", + g_variant_new_string (ostree_deployment_get_bootcsum (deployment))); + + return g_variant_builder_end (&builder); +} + +static gboolean +require_str_key (GVariantDict *dict, + const char *name, + const char **ret, + GError **error) +{ + if (!g_variant_dict_lookup (dict, name, "&s", ret)) + return glnx_throw (error, "Missing key: %s", name); + return TRUE; +} + +/* Reverse of the above; convert a variant to a deployment. Note that the + * deployment may not actually be present; this should be verified by + * higher level code. + */ +OstreeDeployment * +_ostree_sysroot_deserialize_deployment_from_variant (GVariant *v, + GError **error) +{ + g_autoptr(GVariantDict) dict = g_variant_dict_new (v); + const char *name = NULL; + if (!require_str_key (dict, "name", &name, error)) + return FALSE; + const char *bootcsum = NULL; + if (!require_str_key (dict, "bootcsum", &bootcsum, error)) + return FALSE; + const char *osname = NULL; + if (!require_str_key (dict, "osname", &osname, error)) + return FALSE; + g_autofree char *checksum = NULL; + gint deployserial; + if (!_ostree_sysroot_parse_deploy_path_name (name, &checksum, &deployserial, error)) + return NULL; + return ostree_deployment_new (-1, osname, checksum, deployserial, + bootcsum, -1); +} + + +/** + * ostree_sysroot_stage_tree: + * @self: Sysroot + * @osname: (allow-none): osname to use for merge deployment + * @revision: Checksum to add + * @origin: (allow-none): Origin to use for upgrades + * @merge_deployment: (allow-none): Use this deployment for merge path + * @override_kernel_argv: (allow-none) (array zero-terminated=1) (element-type utf8): Use these as kernel arguments; if %NULL, inherit options from provided_merge_deployment + * @out_new_deployment: (out): The new deployment path + * @cancellable: Cancellable + * @error: Error + * + * Like ostree_sysroot_deploy_tree(), but "finalization" only occurs at OS + * shutdown time. + * + * Since: 2018.5 + */ +gboolean +ostree_sysroot_stage_tree (OstreeSysroot *self, + const char *osname, + const char *revision, + GKeyFile *origin, + OstreeDeployment *merge_deployment, + char **override_kernel_argv, + OstreeDeployment **out_new_deployment, + GCancellable *cancellable, + GError **error) +{ + if (!_ostree_sysroot_ensure_writable (self, error)) + return FALSE; + + OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (self); + if (booted_deployment == NULL) + return glnx_throw (error, "Cannot stage a deployment when not currently booted into an OSTree system"); + + /* This is used by the testsuite to exercise the path unit, until it becomes the default + * (which is pending on the preset making it everywhere). */ + if ((self->debug_flags & OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH) == 0) + { + /* This is a bit of a hack. When adding a new service we have to end up getting + * into the presets for downstream distros; see e.g. https://src.fedoraproject.org/rpms/ostree/pull-request/7 + * + * Then again, it's perhaps a bit nicer to only start the service on-demand anyways. + */ + const char *const systemctl_argv[] = {"systemctl", "start", "ostree-finalize-staged.service", NULL}; + int estatus; + if (!g_spawn_sync (NULL, (char**)systemctl_argv, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, NULL, &estatus, error)) + return FALSE; + if (!g_spawn_check_exit_status (estatus, error)) + return FALSE; + } + else + { + g_print ("test-staged-path: Not running `systemctl start`\n"); + } /* OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH */ + + g_autoptr(OstreeDeployment) deployment = NULL; + if (!sysroot_initialize_deployment (self, osname, revision, origin, override_kernel_argv, + &deployment, cancellable, error)) + return FALSE; + + /* Write out the origin file using the sepolicy from the non-merged root for + * now (i.e. using /usr/etc policy, not /etc); in practice we don't really + * expect people to customize the label for it. + */ + { g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); + glnx_autofd int deployment_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, deployment_path, FALSE, + &deployment_dfd, error)) + return FALSE; + g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error); + if (!sepolicy) + return FALSE; + if (!write_origin_file_internal (self, sepolicy, deployment, + ostree_deployment_get_origin (deployment), + GLNX_FILE_REPLACE_NODATASYNC, + cancellable, error)) + return FALSE; + } + + /* After here we defer action until shutdown. The remaining arguments (merge + * deployment, kargs) are serialized to a state file in /run. + */ + + /* "target" is the staged deployment */ + g_autoptr(GVariantBuilder) builder = g_variant_builder_new ((GVariantType*)"a{sv}"); + g_variant_builder_add (builder, "{sv}", "target", + serialize_deployment_to_variant (deployment)); + + if (merge_deployment) + g_variant_builder_add (builder, "{sv}", "merge-deployment", + serialize_deployment_to_variant (merge_deployment)); + + if (override_kernel_argv) + g_variant_builder_add (builder, "{sv}", "kargs", + g_variant_new_strv ((const char *const*)override_kernel_argv, -1)); + + const char *parent = dirname (strdupa (_OSTREE_SYSROOT_RUNSTATE_STAGED)); + if (!glnx_shutil_mkdir_p_at (AT_FDCWD, parent, 0755, cancellable, error)) + return FALSE; + + g_autoptr(GVariant) state = g_variant_ref_sink (g_variant_builder_end (builder)); + if (!glnx_file_replace_contents_at (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, + g_variant_get_data (state), g_variant_get_size (state), + GLNX_FILE_REPLACE_NODATASYNC, + cancellable, error)) + return FALSE; + + /* If we have a previous one, clean it up */ + if (self->staged_deployment) + { + if (!_ostree_sysroot_rmrf_deployment (self, self->staged_deployment, cancellable, error)) + return FALSE; + } + + /* Bump mtime so external processes know something changed, and then reload. */ + if (!_ostree_sysroot_bump_mtime (self, error)) + return FALSE; + if (!ostree_sysroot_load (self, cancellable, error)) + return FALSE; + /* Like deploy, we do a prepare cleanup; among other things, this ensures + * that a ref will be written for the staged tree. See also + * https://github.com/ostreedev/ostree/pull/1566 though which + * adds an ostree_sysroot_cleanup_prune() API. + */ + if (!ostree_sysroot_prepare_cleanup (self, cancellable, error)) + return FALSE; + + ot_transfer_out_value (out_new_deployment, &deployment); + return TRUE; +} + +/* Invoked at shutdown time by ostree-finalize-staged.service */ +gboolean +_ostree_sysroot_finalize_staged (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + /* It's totally fine if there's no staged deployment; perhaps down the line + * though we could teach the ostree cmdline to tell systemd to activate the + * service when a staged deployment is created. + */ + if (!self->staged_deployment) + { + ot_journal_print (LOG_INFO, "No deployment staged for finalization"); + return TRUE; + } + + /* Check if finalization is locked. */ + if (!glnx_fstatat_allow_noent (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED_LOCKED, + NULL, 0, error)) + return FALSE; + if (errno == 0) + { + ot_journal_print (LOG_INFO, "Not finalizing; found " + _OSTREE_SYSROOT_RUNSTATE_STAGED_LOCKED); + return TRUE; + } + + /* Notice we send this *after* the trivial `return TRUE` above; this msg implies we've + * committed to finalizing the deployment. */ + ot_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, + SD_ID128_FORMAT_VAL(OSTREE_DEPLOYMENT_FINALIZING_ID), + "MESSAGE=Finalizing staged deployment", + "OSTREE_OSNAME=%s", + ostree_deployment_get_osname (self->staged_deployment), + "OSTREE_CHECKSUM=%s", + ostree_deployment_get_csum (self->staged_deployment), + "OSTREE_DEPLOYSERIAL=%u", + ostree_deployment_get_deployserial (self->staged_deployment), + NULL); + + g_assert (self->staged_deployment_data); + + g_autoptr(OstreeDeployment) merge_deployment = NULL; + g_autoptr(GVariant) merge_deployment_v = NULL; + if (g_variant_lookup (self->staged_deployment_data, "merge-deployment", "@a{sv}", + &merge_deployment_v)) + { + g_autoptr(OstreeDeployment) merge_deployment_stub = + _ostree_sysroot_deserialize_deployment_from_variant (merge_deployment_v, error); + if (!merge_deployment_stub) + return FALSE; + for (guint i = 0; i < self->deployments->len; i++) + { + OstreeDeployment *deployment = self->deployments->pdata[i]; + if (ostree_deployment_equal (deployment, merge_deployment_stub)) + { + merge_deployment = g_object_ref (deployment); + break; + } + } + + if (!merge_deployment) + return glnx_throw (error, "Failed to find merge deployment %s.%d for staged", + ostree_deployment_get_csum (merge_deployment_stub), + ostree_deployment_get_deployserial (merge_deployment_stub)); + } + g_autofree char **kargs = NULL; + g_variant_lookup (self->staged_deployment_data, "kargs", "^a&s", &kargs); + + /* Unlink the staged state now; if we're interrupted in the middle, + * we don't want e.g. deal with the partially written /etc merge. + */ + if (!glnx_unlinkat (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, 0, error)) + return FALSE; + + if (!sysroot_finalize_deployment (self, self->staged_deployment, kargs, merge_deployment, + cancellable, error)) + return FALSE; + + /* Now, take ownership of the staged state, as normally the API below strips + * it out. + */ + g_autoptr(OstreeDeployment) staged = g_steal_pointer (&self->staged_deployment); + staged->staged = FALSE; + g_ptr_array_remove_index (self->deployments, 0); + + /* TODO: Proxy across flags too? + * + * But note that we always use NO_CLEAN to avoid adding more latency at + * shutdown, and also because e.g. rpm-ostree wants to own the cleanup + * process. + */ + OstreeSysrootSimpleWriteDeploymentFlags flags = + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN; + if (!ostree_sysroot_simple_write_deployment (self, ostree_deployment_get_osname (staged), + staged, merge_deployment, flags, + cancellable, error)) + return FALSE; + + /* Do the basic cleanup that may impact /boot, but not the repo pruning */ + if (!ostree_sysroot_prepare_cleanup (self, cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_deployment_set_kargs: + * @self: Sysroot + * @deployment: A deployment + * @new_kargs: (array zero-terminated=1) (element-type utf8): Replace deployment's kernel arguments + * @cancellable: Cancellable + * @error: Error + * + * Entirely replace the kernel arguments of @deployment with the + * values in @new_kargs. + */ +gboolean +ostree_sysroot_deployment_set_kargs (OstreeSysroot *self, + OstreeDeployment *deployment, + char **new_kargs, + GCancellable *cancellable, + GError **error) +{ + if (!_ostree_sysroot_ensure_writable (self, error)) + return FALSE; + + /* For now; instead of this do a redeployment */ + g_assert (!ostree_deployment_is_staged (deployment)); + + g_autoptr(OstreeDeployment) new_deployment = ostree_deployment_clone (deployment); + OstreeBootconfigParser *new_bootconfig = ostree_deployment_get_bootconfig (new_deployment); + + g_autoptr(OstreeKernelArgs) kargs = ostree_kernel_args_new (); + ostree_kernel_args_append_argv (kargs, new_kargs); + g_autofree char *new_options = ostree_kernel_args_to_string (kargs); + ostree_bootconfig_parser_set (new_bootconfig, "options", new_options); + + g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); + for (guint i = 0; i < self->deployments->len; i++) + { + OstreeDeployment *cur = self->deployments->pdata[i]; + if (cur == deployment) + g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); + else + g_ptr_array_add (new_deployments, g_object_ref (cur)); + } + + if (!ostree_sysroot_write_deployments (self, new_deployments, + cancellable, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_deployment_set_mutable: + * @self: Sysroot + * @deployment: A deployment + * @is_mutable: Whether or not deployment's files can be changed + * @cancellable: Cancellable + * @error: Error + * + * By default, deployment directories are not mutable. This function + * will allow making them temporarily mutable, for example to allow + * layering additional non-OSTree content. + */ +gboolean +ostree_sysroot_deployment_set_mutable (OstreeSysroot *self, + OstreeDeployment *deployment, + gboolean is_mutable, + GCancellable *cancellable, + GError **error) +{ + if (!_ostree_sysroot_ensure_writable (self, error)) + return FALSE; + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); + glnx_autofd int fd = -1; + if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &fd, error)) + return FALSE; + + if (!_ostree_linuxfs_fd_alter_immutable_flag (fd, !is_mutable, cancellable, error)) + return FALSE; + + return TRUE; +} diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h new file mode 100644 index 0000000..96670b1 --- /dev/null +++ b/src/libostree/ostree-sysroot-private.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2012,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "libglnx.h" +#include "ostree.h" +#include "ostree-bootloader.h" + +G_BEGIN_DECLS + +typedef enum { + + /* Don't flag deployments as immutable. */ + OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS = 1 << 0, + /* See https://github.com/ostreedev/ostree/pull/759 */ + OSTREE_SYSROOT_DEBUG_NO_XATTRS = 1 << 1, + /* https://github.com/ostreedev/ostree/pull/1049 */ + OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE = 1 << 2, + /* This is a temporary flag until we fully drop the explicit `systemctl start + * ostree-finalize-staged.service` so that tests can exercise the new path unit. */ + OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH = 1 << 3, +} OstreeSysrootDebugFlags; + +typedef enum { + OSTREE_SYSROOT_LOAD_STATE_NONE, /* ostree_sysroot_new() was called */ + OSTREE_SYSROOT_LOAD_STATE_INIT, /* We've loaded basic sysroot state and have an fd */ + OSTREE_SYSROOT_LOAD_STATE_LOADED, /* We've loaded all of the deployments */ +} OstreeSysrootLoadState; + +/** + * OstreeSysroot: + * Internal struct + */ +struct OstreeSysroot { + GObject parent; + + GFile *path; + int sysroot_fd; + GLnxLockFile lock; + + OstreeSysrootLoadState loadstate; + gboolean mount_namespace_in_use; /* TRUE if caller has told us they used CLONE_NEWNS */ + gboolean root_is_ostree_booted; /* TRUE if sysroot is / and we are booted via ostree */ + /* The device/inode for /, used to detect booted deployment */ + dev_t root_device; + ino_t root_inode; + + gboolean is_physical; /* TRUE if we're pointed at physical storage root and not a deployment */ + GPtrArray *deployments; + int bootversion; + int subbootversion; + OstreeDeployment *booted_deployment; + OstreeDeployment *staged_deployment; + GVariant *staged_deployment_data; + struct timespec loaded_ts; + + /* Only access through ostree_sysroot_[_get]repo() */ + OstreeRepo *repo; + + OstreeSysrootDebugFlags debug_flags; +}; + +#define OSTREE_SYSROOT_LOCKFILE "ostree/lock" +/* We keep some transient state in /run */ +#define _OSTREE_SYSROOT_RUNSTATE_STAGED "/run/ostree/staged-deployment" +#define _OSTREE_SYSROOT_RUNSTATE_STAGED_LOCKED "/run/ostree/staged-deployment-locked" +#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/" +#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development" + +gboolean +_ostree_sysroot_ensure_writable (OstreeSysroot *self, + GError **error); + +void +_ostree_sysroot_emit_journal_msg (OstreeSysroot *self, + const char *msg); + +gboolean +_ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, + int bootversion, + GPtrArray **out_loader_configs, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_sysroot_read_current_subbootversion (OstreeSysroot *self, + int bootversion, + int *out_subbootversion, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_sysroot_parse_deploy_path_name (const char *name, + char **out_csum, + int *out_serial, + GError **error); + +gboolean +_ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd, + const char *osname, + GPtrArray *inout_deployments, + GCancellable *cancellable, + GError **error); + +void +_ostree_deployment_set_bootconfig_from_kargs (OstreeDeployment *deployment, + char **override_kernel_argv); + +gboolean +_ostree_sysroot_reload_staged (OstreeSysroot *self, GError **error); + +gboolean +_ostree_sysroot_finalize_staged (OstreeSysroot *self, + GCancellable *cancellable, + GError **error); + +OstreeDeployment * +_ostree_sysroot_deserialize_deployment_from_variant (GVariant *v, + GError **error); + +char * +_ostree_sysroot_get_origin_relpath (GFile *path, + guint32 *out_device, + guint64 *out_inode, + GCancellable *cancellable, + GError **error); + +gboolean +_ostree_sysroot_rmrf_deployment (OstreeSysroot *sysroot, + OstreeDeployment *deployment, + GCancellable *cancellable, + GError **error); + +char * _ostree_sysroot_get_runstate_path (OstreeDeployment *deployment, const char *key); + +char *_ostree_sysroot_join_lines (GPtrArray *lines); + +gboolean _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot, + OstreeBootloader **out_bootloader, + GCancellable *cancellable, + GError **error); + +gboolean _ostree_sysroot_bump_mtime (OstreeSysroot *sysroot, + GError **error); + +gboolean _ostree_sysroot_cleanup_internal (OstreeSysroot *sysroot, + gboolean prune_repo, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-sysroot-upgrader.c b/src/libostree/ostree-sysroot-upgrader.c new file mode 100644 index 0000000..4681335 --- /dev/null +++ b/src/libostree/ostree-sysroot-upgrader.c @@ -0,0 +1,699 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" + +#include "ostree.h" +#include "ostree-sysroot-upgrader.h" +#include "ostree-core-private.h" + +/** + * SECTION:ostree-sysroot-upgrader + * @title: Simple upgrade class + * @short_description: Upgrade OSTree systems + * + * The #OstreeSysrootUpgrader class allows performing simple upgrade + * operations. + */ +typedef struct { + GObjectClass parent_class; +} OstreeSysrootUpgraderClass; + +struct OstreeSysrootUpgrader { + GObject parent; + + OstreeSysroot *sysroot; + char *osname; + OstreeSysrootUpgraderFlags flags; + + OstreeDeployment *merge_deployment; + GKeyFile *origin; + char *origin_remote; + char *origin_ref; + char *override_csum; + + char *new_revision; +}; + +enum { + PROP_0, + + PROP_SYSROOT, + PROP_OSNAME, + PROP_FLAGS +}; + +static void ostree_sysroot_upgrader_initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (OstreeSysrootUpgrader, ostree_sysroot_upgrader, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, ostree_sysroot_upgrader_initable_iface_init)) + +static gboolean +parse_refspec (OstreeSysrootUpgrader *self, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *origin_refspec = NULL; + g_autofree char *unconfigured_state = NULL; + g_autofree char *csum = NULL; + + if ((self->flags & OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED) == 0) + { + /* If explicit action by the OS creator is requried to upgrade, print their text as an error. + * NOTE: If changing this, see the matching implementation in ostree-repo-pull.c. + */ + unconfigured_state = g_key_file_get_string (self->origin, "origin", "unconfigured-state", NULL); + if (unconfigured_state) + return glnx_throw (error, "origin unconfigured-state: %s", unconfigured_state); + } + + origin_refspec = g_key_file_get_string (self->origin, "origin", "refspec", NULL); + if (!origin_refspec) + return glnx_throw (error, "No origin/refspec in current deployment origin; cannot upgrade via ostree"); + + g_clear_pointer (&self->origin_remote, g_free); + g_clear_pointer (&self->origin_ref, g_free); + if (!ostree_parse_refspec (origin_refspec, + &self->origin_remote, + &self->origin_ref, + error)) + return FALSE; + + csum = g_key_file_get_string (self->origin, "origin", "override-commit", NULL); + if (csum != NULL && !ostree_validate_checksum_string (csum, error)) + return FALSE; + g_clear_pointer (&self->override_csum, g_free); + self->override_csum = g_steal_pointer (&csum); + + return TRUE; +} + +static gboolean +ostree_sysroot_upgrader_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + OstreeSysrootUpgrader *self = (OstreeSysrootUpgrader*)initable; + OstreeDeployment *booted_deployment = + ostree_sysroot_get_booted_deployment (self->sysroot); + + if (booted_deployment == NULL && self->osname == NULL) + return glnx_throw (error, "Not currently booted into an OSTree system and no OS specified"); + + if (self->osname == NULL) + { + g_assert (booted_deployment); + self->osname = g_strdup (ostree_deployment_get_osname (booted_deployment)); + } + else if (self->osname[0] == '\0') + return glnx_throw (error, "Invalid empty osname"); + + self->merge_deployment = ostree_sysroot_get_merge_deployment (self->sysroot, self->osname); + if (self->merge_deployment == NULL) + return glnx_throw (error, "No previous deployment for OS '%s'", self->osname); + + self->origin = ostree_deployment_get_origin (self->merge_deployment); + if (!self->origin) + return glnx_throw (error, "No origin known for deployment %s.%d", + ostree_deployment_get_csum (self->merge_deployment), + ostree_deployment_get_deployserial (self->merge_deployment)); + g_key_file_ref (self->origin); + + if (!parse_refspec (self, cancellable, error)) + return FALSE; + + return TRUE; +} + +static void +ostree_sysroot_upgrader_initable_iface_init (GInitableIface *iface) +{ + iface->init = ostree_sysroot_upgrader_initable_init; +} + +static void +ostree_sysroot_upgrader_finalize (GObject *object) +{ + OstreeSysrootUpgrader *self = OSTREE_SYSROOT_UPGRADER (object); + + g_clear_object (&self->sysroot); + g_free (self->osname); + + g_clear_object (&self->merge_deployment); + if (self->origin) + g_key_file_unref (self->origin); + g_free (self->origin_remote); + g_free (self->origin_ref); + g_free (self->override_csum); + g_free (self->new_revision); + + G_OBJECT_CLASS (ostree_sysroot_upgrader_parent_class)->finalize (object); +} + +static void +ostree_sysroot_upgrader_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeSysrootUpgrader *self = OSTREE_SYSROOT_UPGRADER (object); + + switch (prop_id) + { + case PROP_SYSROOT: + self->sysroot = g_value_dup_object (value); + break; + case PROP_OSNAME: + self->osname = g_value_dup_string (value); + break; + case PROP_FLAGS: + self->flags = g_value_get_flags (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_sysroot_upgrader_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeSysrootUpgrader *self = OSTREE_SYSROOT_UPGRADER (object); + + switch (prop_id) + { + case PROP_SYSROOT: + g_value_set_object (value, self->sysroot); + break; + case PROP_OSNAME: + g_value_set_string (value, self->osname); + break; + case PROP_FLAGS: + g_value_set_flags (value, self->flags); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_sysroot_upgrader_constructed (GObject *object) +{ + OstreeSysrootUpgrader *self = OSTREE_SYSROOT_UPGRADER (object); + + g_assert (self->sysroot != NULL); + + G_OBJECT_CLASS (ostree_sysroot_upgrader_parent_class)->constructed (object); +} + +static void +ostree_sysroot_upgrader_class_init (OstreeSysrootUpgraderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = ostree_sysroot_upgrader_constructed; + object_class->get_property = ostree_sysroot_upgrader_get_property; + object_class->set_property = ostree_sysroot_upgrader_set_property; + object_class->finalize = ostree_sysroot_upgrader_finalize; + + g_object_class_install_property (object_class, + PROP_SYSROOT, + g_param_spec_object ("sysroot", "", "", + OSTREE_TYPE_SYSROOT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_OSNAME, + g_param_spec_string ("osname", "", "", NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, + PROP_FLAGS, + g_param_spec_flags ("flags", "", "", + ostree_sysroot_upgrader_flags_get_type (), + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +} + +static void +ostree_sysroot_upgrader_init (OstreeSysrootUpgrader *self) +{ +} + +/** + * ostree_sysroot_upgrader_new: + * @sysroot: An #OstreeSysroot + * @cancellable: Cancellable + * @error: Error + * + * Returns: (transfer full): An upgrader + */ +OstreeSysrootUpgrader* +ostree_sysroot_upgrader_new (OstreeSysroot *sysroot, + GCancellable *cancellable, + GError **error) +{ + return g_initable_new (OSTREE_TYPE_SYSROOT_UPGRADER, cancellable, error, + "sysroot", sysroot, NULL); +} + +/** + * ostree_sysroot_upgrader_new_for_os: + * @sysroot: An #OstreeSysroot + * @osname: (allow-none): Operating system name + * @cancellable: Cancellable + * @error: Error + * + * Returns: (transfer full): An upgrader + */ +OstreeSysrootUpgrader* +ostree_sysroot_upgrader_new_for_os (OstreeSysroot *sysroot, + const char *osname, + GCancellable *cancellable, + GError **error) +{ + return g_initable_new (OSTREE_TYPE_SYSROOT_UPGRADER, cancellable, error, + "sysroot", sysroot, "osname", osname, NULL); +} + +/** + * ostree_sysroot_upgrader_new_for_os_with_flags: + * @sysroot: An #OstreeSysroot + * @osname: (allow-none): Operating system name + * @flags: Flags + * @cancellable: Cancellable + * @error: Error + * + * Returns: (transfer full): An upgrader + */ +OstreeSysrootUpgrader * +ostree_sysroot_upgrader_new_for_os_with_flags (OstreeSysroot *sysroot, + const char *osname, + OstreeSysrootUpgraderFlags flags, + GCancellable *cancellable, + GError **error) +{ + return g_initable_new (OSTREE_TYPE_SYSROOT_UPGRADER, cancellable, error, + "sysroot", sysroot, "osname", osname, "flags", flags, NULL); +} + +/** + * ostree_sysroot_upgrader_get_origin: + * @self: Sysroot + * + * Returns: (transfer none): The origin file, or %NULL if unknown + */ +GKeyFile * +ostree_sysroot_upgrader_get_origin (OstreeSysrootUpgrader *self) +{ + return self->origin; +} + +/** + * ostree_sysroot_upgrader_dup_origin: + * @self: Sysroot + * + * Returns: (transfer full): A copy of the origin file, or %NULL if unknown + */ +GKeyFile * +ostree_sysroot_upgrader_dup_origin (OstreeSysrootUpgrader *self) +{ + GKeyFile *copy = NULL; + + g_return_val_if_fail (OSTREE_IS_SYSROOT_UPGRADER (self), NULL); + + if (self->origin != NULL) + { + g_autofree char *data = NULL; + gsize length = 0; + + copy = g_key_file_new (); + data = g_key_file_to_data (self->origin, &length, NULL); + g_key_file_load_from_data (copy, data, length, + G_KEY_FILE_KEEP_COMMENTS, NULL); + } + + return copy; +} + +/** + * ostree_sysroot_upgrader_set_origin: + * @self: Sysroot + * @origin: (allow-none): The new origin + * @cancellable: Cancellable + * @error: Error + * + * Replace the origin with @origin. + */ +gboolean +ostree_sysroot_upgrader_set_origin (OstreeSysrootUpgrader *self, + GKeyFile *origin, + GCancellable *cancellable, + GError **error) +{ + g_clear_pointer (&self->origin, g_key_file_unref); + if (origin) + { + self->origin = g_key_file_ref (origin); + if (!parse_refspec (self, cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/** + * ostree_sysroot_upgrader_get_origin_description: + * @self: Upgrader + * + * Returns: A one-line descriptive summary of the origin, or %NULL if unknown + */ +char * +ostree_sysroot_upgrader_get_origin_description (OstreeSysrootUpgrader *self) +{ + if (!self->origin) + return NULL; + return g_key_file_get_string (self->origin, "origin", "refspec", NULL); +} + +/** + * ostree_sysroot_upgrader_check_timestamps: + * @repo: Repo + * @from_rev: From revision + * @to_rev: To revision + * @error: Error + * + * Check that the timestamp on @to_rev is equal to or newer than + * @from_rev. This protects systems against man-in-the-middle + * attackers which provide a client with an older commit. + */ +gboolean +ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo, + const char *from_rev, + const char *to_rev, + GError **error) +{ + g_autoptr(GVariant) old_commit = NULL; + if (!ostree_repo_load_variant (repo, + OSTREE_OBJECT_TYPE_COMMIT, + from_rev, + &old_commit, + error)) + return FALSE; + + g_autoptr(GVariant) new_commit = NULL; + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + to_rev, &new_commit, + error)) + return FALSE; + + if (!_ostree_compare_timestamps (from_rev, ostree_commit_get_timestamp (old_commit), + to_rev, ostree_commit_get_timestamp (new_commit), + error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_upgrader_pull: + * @self: Upgrader + * @flags: Flags controlling pull behavior + * @upgrader_flags: Flags controlling upgrader behavior + * @progress: (allow-none): Progress + * @out_changed: (out): Whether or not the origin changed + * @cancellable: Cancellable + * @error: Error + * + * Perform a pull from the origin. First check if the ref has + * changed, if so download the linked objects, and store the updated + * ref locally. Then @out_changed will be %TRUE. + * + * If the origin remote is unchanged, @out_changed will be set to + * %FALSE. + */ +gboolean +ostree_sysroot_upgrader_pull (OstreeSysrootUpgrader *self, + OstreeRepoPullFlags flags, + OstreeSysrootUpgraderPullFlags upgrader_flags, + OstreeAsyncProgress *progress, + gboolean *out_changed, + GCancellable *cancellable, + GError **error) +{ + return ostree_sysroot_upgrader_pull_one_dir (self, NULL, flags, upgrader_flags, progress, out_changed, cancellable, error); +} + +/** + * ostree_sysroot_upgrader_pull_one_dir: + * @self: Upgrader + * @dir_to_pull: Subdirectory path (should include a leading /) + * @flags: Flags controlling pull behavior + * @upgrader_flags: Flags controlling upgrader behavior + * @progress: (allow-none): Progress + * @out_changed: (out): Whether or not the origin changed + * @cancellable: Cancellable + * @error: Error + * + * Like ostree_sysroot_upgrader_pull(), but allows retrieving just a + * subpath of the tree. This can be used to download metadata files + * from inside the tree such as package databases. + * + */ +gboolean +ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, + const char *dir_to_pull, + OstreeRepoPullFlags flags, + OstreeSysrootUpgraderPullFlags upgrader_flags, + OstreeAsyncProgress *progress, + gboolean *out_changed, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepo) repo = NULL; + char *refs_to_fetch[] = { NULL, NULL }; + const char *from_revision = NULL; + g_autofree char *origin_refspec = NULL; + g_autofree char *new_revision = NULL; + g_autoptr(GVariant) new_variant = NULL; + g_autoptr(GVariant) new_metadata = NULL; + g_autoptr(GVariant) rebase = NULL; + + if (self->override_csum != NULL) + refs_to_fetch[0] = self->override_csum; + else + refs_to_fetch[0] = self->origin_ref; + + if (!ostree_sysroot_get_repo (self->sysroot, &repo, cancellable, error)) + return FALSE; + + if (self->origin_remote) + origin_refspec = g_strconcat (self->origin_remote, ":", self->origin_ref, NULL); + else + origin_refspec = g_strdup (self->origin_ref); + + g_assert (self->merge_deployment); + from_revision = ostree_deployment_get_csum (self->merge_deployment); + + if (self->origin_remote && + (upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC) == 0) + { + g_autoptr(GVariantBuilder) optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + if (dir_to_pull && *dir_to_pull) + g_variant_builder_add (optbuilder, "{s@v}", "subdir", + g_variant_new_variant (g_variant_new_string (dir_to_pull))); + g_variant_builder_add (optbuilder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (flags))); + /* Add the timestamp check, unless disabled */ + if ((upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER) == 0) + g_variant_builder_add (optbuilder, "{s@v}", "timestamp-check-from-rev", + g_variant_new_variant (g_variant_new_string (from_revision))); + + g_variant_builder_add (optbuilder, "{s@v}", "refs", + g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch, -1))); + g_autoptr(GVariant) opts = g_variant_ref_sink (g_variant_builder_end (optbuilder)); + if (!ostree_repo_pull_with_options (repo, self->origin_remote, + opts, progress, + cancellable, error)) + return FALSE; + + if (progress) + ostree_async_progress_finish (progress); + } + + /* Check to see if the commit marks the ref as EOL, redirecting to + * another. */ + if (!ostree_repo_resolve_rev (repo, origin_refspec, FALSE, + &new_revision, error)) + return FALSE; + + if (!ostree_repo_load_variant (repo, + OSTREE_OBJECT_TYPE_COMMIT, + new_revision, + &new_variant, + error)) + return FALSE; + + g_variant_get_child (new_variant, 0, "@a{sv}", &new_metadata); + rebase = g_variant_lookup_value (new_metadata, OSTREE_COMMIT_META_KEY_ENDOFLIFE_REBASE, G_VARIANT_TYPE_STRING); + if (rebase) + { + const char *new_ref = g_variant_get_string (rebase, 0); + + /* Pull the new ref */ + if (self->origin_remote && + (upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC) == 0) + { + refs_to_fetch[0] = (char *) new_ref; + if (!ostree_repo_pull_one_dir (repo, self->origin_remote, dir_to_pull, refs_to_fetch, + flags, progress, cancellable, error)) + return FALSE; + } + + /* Use the new ref for the rest of the update process */ + g_free (self->origin_ref); + self->origin_ref = g_strdup(new_ref); + g_free (origin_refspec); + + if (self->origin_remote) + origin_refspec = g_strconcat (self->origin_remote, ":", new_ref, NULL); + else + origin_refspec = g_strdup (new_ref); + + g_key_file_set_string (self->origin, "origin", "refspec", origin_refspec); + } + + if (self->override_csum != NULL) + { + if (!ostree_repo_set_ref_immediate (repo, + self->origin_remote, + self->origin_ref, + self->override_csum, + cancellable, + error)) + return FALSE; + + self->new_revision = g_strdup (self->override_csum); + } + else + { + if (!ostree_repo_resolve_rev (repo, origin_refspec, FALSE, + &self->new_revision, error)) + return FALSE; + + } + + if (g_strcmp0 (from_revision, self->new_revision) == 0) + { + *out_changed = FALSE; + } + else + { + gboolean allow_older = (upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER) > 0; + + *out_changed = TRUE; + + if (from_revision && !allow_older) + { + if (!ostree_sysroot_upgrader_check_timestamps (repo, from_revision, + self->new_revision, + error)) + return FALSE; + } + } + + return TRUE; +} + +/** + * ostree_sysroot_upgrader_deploy: + * @self: Self + * @cancellable: Cancellable + * @error: Error + * + * Write the new deployment to disk, perform a configuration merge + * with /etc, and update the bootloader configuration. + */ +gboolean +ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeDeployment) new_deployment = NULL; + + /* Experimental flag to enable staging */ + if (getenv ("OSTREE_EX_STAGE_DEPLOYMENTS")) + { + if (!ostree_sysroot_stage_tree (self->sysroot, self->osname, + self->new_revision, + self->origin, + self->merge_deployment, + NULL, + &new_deployment, + cancellable, error)) + return FALSE; + } + else + { + if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname, + self->new_revision, + self->origin, + self->merge_deployment, + NULL, + &new_deployment, + cancellable, error)) + return FALSE; + + if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname, + new_deployment, + self->merge_deployment, + 0, + cancellable, error)) + return FALSE; + } + + return TRUE; +} + +GType +ostree_sysroot_upgrader_flags_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const GFlagsValue values[] = { + { OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED, "OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED", "ignore-unconfigured" }, + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_flags_register_static (g_intern_static_string ("OstreeSysrootUpgraderFlags"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} diff --git a/src/libostree/ostree-sysroot-upgrader.h b/src/libostree/ostree-sysroot-upgrader.h new file mode 100644 index 0000000..c9bf8a1 --- /dev/null +++ b/src/libostree/ostree-sysroot-upgrader.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-sysroot.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_SYSROOT_UPGRADER ostree_sysroot_upgrader_get_type() +#define OSTREE_SYSROOT_UPGRADER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_SYSROOT_UPGRADER, OstreeSysrootUpgrader)) +#define OSTREE_IS_SYSROOT_UPGRADER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_SYSROOT_UPGRADER)) + +/** + * OstreeSysrootUpgraderFlags: + * @OSTREE_SYSROOT_UPGRADER_FLAGS_NONE: No options + * @OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED: Do not error if the origin has an unconfigured-state key + * + * Flags controlling operation of an #OstreeSysrootUpgrader. + */ +typedef enum { + OSTREE_SYSROOT_UPGRADER_FLAGS_NONE = (1 << 0), + OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED = (1 << 1), +} OstreeSysrootUpgraderFlags; + +_OSTREE_PUBLIC +GType ostree_sysroot_upgrader_get_type (void); + +_OSTREE_PUBLIC +GType ostree_sysroot_upgrader_flags_get_type (void); + +_OSTREE_PUBLIC +OstreeSysrootUpgrader *ostree_sysroot_upgrader_new (OstreeSysroot *sysroot, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeSysrootUpgrader *ostree_sysroot_upgrader_new_for_os (OstreeSysroot *sysroot, + const char *osname, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeSysrootUpgrader *ostree_sysroot_upgrader_new_for_os_with_flags (OstreeSysroot *sysroot, + const char *osname, + OstreeSysrootUpgraderFlags flags, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +GKeyFile *ostree_sysroot_upgrader_get_origin (OstreeSysrootUpgrader *self); +_OSTREE_PUBLIC +GKeyFile *ostree_sysroot_upgrader_dup_origin (OstreeSysrootUpgrader *self); +_OSTREE_PUBLIC +gboolean ostree_sysroot_upgrader_set_origin (OstreeSysrootUpgrader *self, GKeyFile *origin, + GCancellable *cancellable, GError **error); + +_OSTREE_PUBLIC +char *ostree_sysroot_upgrader_get_origin_description (OstreeSysrootUpgrader *self); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo, + const char *from_rev, + const char *to_rev, + GError **error); + +typedef enum { + OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_NONE = 0, + OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER = (1 << 0), + OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC = (1 << 1) /* Don't actually do a pull, just check timestamps/changed */ +} OstreeSysrootUpgraderPullFlags; + +_OSTREE_PUBLIC +gboolean ostree_sysroot_upgrader_pull (OstreeSysrootUpgrader *self, + OstreeRepoPullFlags flags, + OstreeSysrootUpgraderPullFlags upgrader_flags, + OstreeAsyncProgress *progress, + gboolean *out_changed, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, + const char *dir_to_pull, + OstreeRepoPullFlags flags, + OstreeSysrootUpgraderPullFlags upgrader_flags, + OstreeAsyncProgress *progress, + gboolean *out_changed, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c new file mode 100644 index 0000000..0dc7a39 --- /dev/null +++ b/src/libostree/ostree-sysroot.c @@ -0,0 +1,2107 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" +#include +#include +#include +#include + +#include "ostree.h" +#include "ostree-core-private.h" +#include "ostree-repo-private.h" +#include "ostree-sepolicy-private.h" +#include "ostree-sysroot-private.h" +#include "ostree-deployment-private.h" +#include "ostree-bootloader-uboot.h" +#include "ostree-bootloader-syslinux.h" +#include "ostree-bootloader-grub2.h" + +/** + * SECTION:ostree-sysroot + * @title: Root partition mount point + * @short_description: Manage physical root filesystem + * + * A #OstreeSysroot object represents a physical root filesystem, + * which in particular should contain a toplevel /ostree directory. + * Inside this directory is an #OstreeRepo in /ostree/repo, plus a set + * of deployments in /ostree/deploy. + * + * This class is not by default safe against concurrent use by threads + * or external processes. You can use ostree_sysroot_lock() to + * perform locking externally. + */ +typedef struct { + GObjectClass parent_class; + + /* Signals */ + void (*journal_msg) (OstreeSysroot *sysroot, + const char *msg); +} OstreeSysrootClass; + +enum { + JOURNAL_MSG_SIGNAL, + LAST_SIGNAL, +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +enum { + PROP_0, + + PROP_PATH +}; + +G_DEFINE_TYPE (OstreeSysroot, ostree_sysroot, G_TYPE_OBJECT) + +static void +ostree_sysroot_finalize (GObject *object) +{ + OstreeSysroot *self = OSTREE_SYSROOT (object); + + g_clear_object (&self->path); + g_clear_object (&self->repo); + g_clear_pointer (&self->deployments, g_ptr_array_unref); + g_clear_object (&self->booted_deployment); + g_clear_object (&self->staged_deployment); + g_clear_pointer (&self->staged_deployment_data, (GDestroyNotify)g_variant_unref); + + glnx_release_lock_file (&self->lock); + + ostree_sysroot_unload (self); + + G_OBJECT_CLASS (ostree_sysroot_parent_class)->finalize (object); +} + +static void +ostree_sysroot_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + OstreeSysroot *self = OSTREE_SYSROOT (object); + + switch (prop_id) + { + case PROP_PATH: + self->path = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_sysroot_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + OstreeSysroot *self = OSTREE_SYSROOT (object); + + switch (prop_id) + { + case PROP_PATH: + g_value_set_object (value, self->path); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ostree_sysroot_constructed (GObject *object) +{ + OstreeSysroot *self = OSTREE_SYSROOT (object); + + /* Ensure the system root path is set. */ + if (self->path == NULL) + self->path = g_object_ref (_ostree_get_default_sysroot_path ()); + + G_OBJECT_CLASS (ostree_sysroot_parent_class)->constructed (object); +} + +static void +ostree_sysroot_class_init (OstreeSysrootClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = ostree_sysroot_constructed; + object_class->get_property = ostree_sysroot_get_property; + object_class->set_property = ostree_sysroot_set_property; + object_class->finalize = ostree_sysroot_finalize; + + g_object_class_install_property (object_class, + PROP_PATH, + g_param_spec_object ("path", + "", + "", + G_TYPE_FILE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * OstreeSysroot::journal-msg: + * @self: Self + * @msg: Human-readable string (should not contain newlines) + * + * libostree will log to the journal various events, such as the /etc merge + * status, and transaction completion. Connect to this signal to also + * synchronously receive the text for those messages. This is intended to be + * used by command line tools which link to libostree as a library. + * + * Currently, the structured data is only available via the systemd journal. + * + * Since: 2017.10 + */ + signals[JOURNAL_MSG_SIGNAL] = + g_signal_new ("journal-msg", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (OstreeSysrootClass, journal_msg), + NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); +} + +static void +ostree_sysroot_init (OstreeSysroot *self) +{ + const GDebugKey keys[] = { + { "mutable-deployments", OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS }, + { "test-fifreeze", OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE }, + { "no-xattrs", OSTREE_SYSROOT_DEBUG_NO_XATTRS }, + { "test-staged-path", OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH }, + }; + + self->debug_flags = g_parse_debug_string (g_getenv ("OSTREE_SYSROOT_DEBUG"), + keys, G_N_ELEMENTS (keys)); + + self->sysroot_fd = -1; +} + +/** + * ostree_sysroot_new: + * @path: (allow-none): Path to a system root directory, or %NULL to use the + * current visible root file system + * + * Create a new #OstreeSysroot object for the sysroot at @path. If @path is %NULL, + * the current visible root file system is used, equivalent to + * ostree_sysroot_new_default(). + * + * Returns: (transfer full): An accessor object for an system root located at @path + */ +OstreeSysroot* +ostree_sysroot_new (GFile *path) +{ + return g_object_new (OSTREE_TYPE_SYSROOT, "path", path, NULL); +} + +/** + * ostree_sysroot_new_default: + * + * Returns: (transfer full): An accessor for the current visible root / filesystem + */ +OstreeSysroot* +ostree_sysroot_new_default (void) +{ + return ostree_sysroot_new (NULL); +} + +/** + * ostree_sysroot_set_mount_namespace_in_use: + * + * If this function is invoked, then libostree will assume that + * a private Linux mount namespace has been created by the process. + * The primary use case for this is to have e.g. /sysroot mounted + * read-only by default. + * + * If this function has been called, then when a function which requires + * writable access is invoked, libostree will automatically remount as writable + * any mount points on which it operates. This currently is just `/sysroot` and + * `/boot`. + * + * If you invoke this function, it must be before ostree_sysroot_load(); it may + * be invoked before or after ostree_sysroot_initialize(). + * + * Since: 2020.1 + */ +void +ostree_sysroot_set_mount_namespace_in_use (OstreeSysroot *self) +{ + /* Must be before we're loaded, as otherwise we'd have to close/reopen all our + fds, e.g. the repo */ + g_return_if_fail (self->loadstate < OSTREE_SYSROOT_LOAD_STATE_LOADED); + self->mount_namespace_in_use = TRUE; +} + +/** + * ostree_sysroot_get_path: + * @self: + * + * Returns: (transfer none): Path to rootfs + */ +GFile * +ostree_sysroot_get_path (OstreeSysroot *self) +{ + return self->path; +} + +/* Open a directory file descriptor for the sysroot if we haven't yet */ +static gboolean +ensure_sysroot_fd (OstreeSysroot *self, + GError **error) +{ + if (self->sysroot_fd == -1) + { + if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->path), TRUE, + &self->sysroot_fd, error)) + return FALSE; + } + return TRUE; +} + +/* Remount /sysroot read-write if necessary */ +gboolean +_ostree_sysroot_ensure_writable (OstreeSysroot *self, + GError **error) +{ + /* Do nothing if no mount namespace is in use */ + if (!self->mount_namespace_in_use) + return TRUE; + + /* If a mount namespace is in use, ensure we're initialized */ + if (!ostree_sysroot_initialize (self, error)) + return FALSE; + + /* If we aren't operating on a booted system, then we don't + * do anything with mounts. + */ + if (!self->root_is_ostree_booted) + return TRUE; + + /* Check if /sysroot is a read-only mountpoint */ + struct statvfs stvfsbuf; + if (statvfs ("/sysroot", &stvfsbuf) < 0) + return glnx_throw_errno_prefix (error, "fstatvfs(/sysroot)"); + if ((stvfsbuf.f_flag & ST_RDONLY) == 0) + return TRUE; + + /* OK, let's remount writable. */ + if (mount ("/sysroot", "/sysroot", NULL, MS_REMOUNT | MS_RELATIME, "") < 0) + return glnx_throw_errno_prefix (error, "Remounting /sysroot read-write"); + + /* Reopen our fd */ + glnx_close_fd (&self->sysroot_fd); + if (!ensure_sysroot_fd (self, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_get_fd: + * @self: Sysroot + * + * Access a file descriptor that refers to the root directory of this sysroot. + * ostree_sysroot_initialize() (or ostree_sysroot_load()) must have been invoked + * prior to calling this function. + * + * Returns: A file descriptor valid for the lifetime of @self + */ +int +ostree_sysroot_get_fd (OstreeSysroot *self) +{ + g_return_val_if_fail (self->sysroot_fd != -1, -1); + return self->sysroot_fd; +} + +/** + * ostree_sysroot_is_booted: + * @self: Sysroot + * + * Can only be invoked after `ostree_sysroot_initialize()`. + * + * Returns: %TRUE iff the sysroot points to a booted deployment + * Since: 2020.1 + */ +gboolean +ostree_sysroot_is_booted (OstreeSysroot *self) +{ + g_return_val_if_fail (self->loadstate >= OSTREE_SYSROOT_LOAD_STATE_INIT, FALSE); + return self->root_is_ostree_booted; +} + +gboolean +_ostree_sysroot_bump_mtime (OstreeSysroot *self, + GError **error) +{ + /* Allow other systems to monitor for changes */ + if (utimensat (self->sysroot_fd, "ostree/deploy", NULL, 0) < 0) + { + glnx_set_prefix_error_from_errno (error, "%s", "futimens"); + return FALSE; + } + return TRUE; +} + +/** + * ostree_sysroot_unload: + * @self: Sysroot + * + * Release any resources such as file descriptors referring to the + * root directory of this sysroot. Normally, those resources are + * cleared by finalization, but in garbage collected languages that + * may not be predictable. + * + * This undoes the effect of `ostree_sysroot_load()`. + */ +void +ostree_sysroot_unload (OstreeSysroot *self) +{ + glnx_close_fd (&self->sysroot_fd); +} + +/** + * ostree_sysroot_ensure_initialized: + * @self: Sysroot + * @cancellable: Cancellable + * @error: Error + * + * Ensure that @self is set up as a valid rootfs, by creating + * /ostree/repo, among other things. + */ +gboolean +ostree_sysroot_ensure_initialized (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + if (!ensure_sysroot_fd (self, error)) + return FALSE; + + if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, "ostree/repo", 0755, + cancellable, error)) + return FALSE; + + if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, "ostree/deploy", 0755, + cancellable, error)) + return FALSE; + + g_autoptr(OstreeRepo) repo = + ostree_repo_create_at (self->sysroot_fd, "ostree/repo", + OSTREE_REPO_MODE_BARE, NULL, + cancellable, error); + if (!repo) + return FALSE; + return TRUE; +} + +void +_ostree_sysroot_emit_journal_msg (OstreeSysroot *self, + const char *msg) +{ + g_signal_emit (self, signals[JOURNAL_MSG_SIGNAL], 0, msg); +} + +gboolean +_ostree_sysroot_parse_deploy_path_name (const char *name, + char **out_csum, + int *out_serial, + GError **error) +{ + + static gsize regex_initialized; + static GRegex *regex; + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^([0-9a-f]+)\\.([0-9]+)$", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + g_autoptr(GMatchInfo) match = NULL; + if (!g_regex_match (regex, name, 0, &match)) + return glnx_throw (error, "Invalid deploy name '%s', expected CHECKSUM.TREESERIAL", name); + + g_autofree char *serial_str = g_match_info_fetch (match, 2); + *out_csum = g_match_info_fetch (match, 1); + *out_serial = (int)g_ascii_strtoll (serial_str, NULL, 10); + return TRUE; +} + +gboolean +_ostree_sysroot_read_current_subbootversion (OstreeSysroot *self, + int bootversion, + int *out_subbootversion, + GCancellable *cancellable, + GError **error) +{ + if (!ensure_sysroot_fd (self, error)) + return FALSE; + + g_autofree char *ostree_bootdir_name = g_strdup_printf ("ostree/boot.%d", bootversion); + struct stat stbuf; + if (!glnx_fstatat_allow_noent (self->sysroot_fd, ostree_bootdir_name, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == ENOENT) + { + *out_subbootversion = 0; + } + else + { + g_autofree char *current_subbootdir_name = + glnx_readlinkat_malloc (self->sysroot_fd, ostree_bootdir_name, + cancellable, error); + if (!current_subbootdir_name) + return FALSE; + + if (g_str_has_suffix (current_subbootdir_name, ".0")) + *out_subbootversion = 0; + else if (g_str_has_suffix (current_subbootdir_name, ".1")) + *out_subbootversion = 1; + else + return glnx_throw (error, "Invalid target '%s' in %s", + current_subbootdir_name, ostree_bootdir_name); + } + + return TRUE; +} + +static gint +compare_boot_loader_configs (OstreeBootconfigParser *a, + OstreeBootconfigParser *b) +{ + const char *a_version = ostree_bootconfig_parser_get (a, "version"); + const char *b_version = ostree_bootconfig_parser_get (b, "version"); + + if (a_version && b_version) + { + int r = strverscmp (a_version, b_version); + /* Reverse */ + return -r; + } + else if (a_version) + return -1; + else + return 1; +} + +static int +compare_loader_configs_for_sorting (gconstpointer a_pp, + gconstpointer b_pp) +{ + OstreeBootconfigParser *a = *((OstreeBootconfigParser**)a_pp); + OstreeBootconfigParser *b = *((OstreeBootconfigParser**)b_pp); + + return compare_boot_loader_configs (a, b); +} + +gboolean +_ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, + int bootversion, + GPtrArray **out_loader_configs, + GCancellable *cancellable, + GError **error) +{ + if (!ensure_sysroot_fd (self, error)) + return FALSE; + + g_autoptr(GPtrArray) ret_loader_configs = + g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + + g_autofree char *entries_path = g_strdup_printf ("boot/loader.%d/entries", bootversion); + gboolean entries_exists; + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!ot_dfd_iter_init_allow_noent (self->sysroot_fd, entries_path, + &dfd_iter, &entries_exists, error)) + return FALSE; + if (!entries_exists) + { + /* Note early return */ + *out_loader_configs = g_steal_pointer (&ret_loader_configs); + return TRUE; + } + + while (TRUE) + { + struct dirent *dent; + struct stat stbuf; + + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + if (!glnx_fstatat (dfd_iter.fd, dent->d_name, &stbuf, 0, error)) + return FALSE; + + if (g_str_has_prefix (dent->d_name, "ostree-") && + g_str_has_suffix (dent->d_name, ".conf") && + S_ISREG (stbuf.st_mode)) + { + g_autoptr(OstreeBootconfigParser) config = ostree_bootconfig_parser_new (); + + if (!ostree_bootconfig_parser_parse_at (config, dfd_iter.fd, dent->d_name, cancellable, error)) + return glnx_prefix_error (error, "Parsing %s", dent->d_name); + + g_ptr_array_add (ret_loader_configs, g_object_ref (config)); + } + } + + /* Callers expect us to give them a sorted array */ + g_ptr_array_sort (ret_loader_configs, compare_loader_configs_for_sorting); + ot_transfer_out_value(out_loader_configs, &ret_loader_configs); + return TRUE; +} + +static gboolean +read_current_bootversion (OstreeSysroot *self, + int *out_bootversion, + GCancellable *cancellable, + GError **error) +{ + int ret_bootversion; + struct stat stbuf; + + if (!glnx_fstatat_allow_noent (self->sysroot_fd, "boot/loader", &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == ENOENT) + { + ret_bootversion = 0; + } + else + { + if (!S_ISLNK (stbuf.st_mode)) + return glnx_throw (error, "Not a symbolic link: boot/loader"); + + g_autofree char *target = + glnx_readlinkat_malloc (self->sysroot_fd, "boot/loader", cancellable, error); + if (!target) + return FALSE; + if (g_strcmp0 (target, "loader.0") == 0) + ret_bootversion = 0; + else if (g_strcmp0 (target, "loader.1") == 0) + ret_bootversion = 1; + else + return glnx_throw (error, "Invalid target '%s' in boot/loader", target); + } + + *out_bootversion = ret_bootversion; + return TRUE; +} + +static gboolean +load_origin (OstreeSysroot *self, + OstreeDeployment *deployment, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *origin_path = ostree_deployment_get_origin_relpath (deployment); + + glnx_autofd int fd = -1; + if (!ot_openat_ignore_enoent (self->sysroot_fd, origin_path, &fd, error)) + return FALSE; + if (fd >= 0) + { + g_autofree char *origin_contents = + glnx_fd_readall_utf8 (fd, NULL, cancellable, error); + if (!origin_contents) + return FALSE; + + g_autoptr(GKeyFile) origin = g_key_file_new (); + if (!g_key_file_load_from_data (origin, origin_contents, -1, 0, error)) + return glnx_prefix_error (error, "Parsing %s", origin_path); + + ostree_deployment_set_origin (deployment, origin); + } + + return TRUE; +} + +static gboolean +parse_bootlink (const char *bootlink, + int *out_entry_bootversion, + char **out_osname, + char **out_bootcsum, + int *out_treebootserial, + GError **error) +{ + static gsize regex_initialized; + static GRegex *regex; + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^/ostree/boot.([01])/([^/]+)/([^/]+)/([0-9]+)$", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + g_autoptr(GMatchInfo) match = NULL; + if (!g_regex_match (regex, bootlink, 0, &match)) + return glnx_throw (error, "Invalid ostree= argument '%s', expected ostree=/ostree/boot.BOOTVERSION/OSNAME/BOOTCSUM/TREESERIAL", bootlink); + + g_autofree char *bootversion_str = g_match_info_fetch (match, 1); + g_autofree char *treebootserial_str = g_match_info_fetch (match, 4); + *out_entry_bootversion = (int)g_ascii_strtoll (bootversion_str, NULL, 10); + *out_osname = g_match_info_fetch (match, 2); + *out_bootcsum = g_match_info_fetch (match, 3); + *out_treebootserial = (int)g_ascii_strtoll (treebootserial_str, NULL, 10); + return TRUE; +} + +char * +_ostree_sysroot_get_runstate_path (OstreeDeployment *deployment, const char *key) +{ + return g_strdup_printf ("%s%s.%d/%s", + _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR, + ostree_deployment_get_csum (deployment), + ostree_deployment_get_deployserial (deployment), + key); +} + +static gboolean +parse_deployment (OstreeSysroot *self, + const char *boot_link, + OstreeDeployment **out_deployment, + GCancellable *cancellable, + GError **error) +{ + if (!ensure_sysroot_fd (self, error)) + return FALSE; + + int entry_boot_version; + g_autofree char *osname = NULL; + g_autofree char *bootcsum = NULL; + int treebootserial = -1; + if (!parse_bootlink (boot_link, &entry_boot_version, + &osname, &bootcsum, &treebootserial, + error)) + return FALSE; + + g_autofree char *errprefix = + g_strdup_printf ("Parsing deployment %i in stateroot '%s'", treebootserial, osname); + GLNX_AUTO_PREFIX_ERROR(errprefix, error); + + const char *relative_boot_link = boot_link; + if (*relative_boot_link == '/') + relative_boot_link++; + + g_autofree char *treebootserial_target = + glnx_readlinkat_malloc (self->sysroot_fd, relative_boot_link, + cancellable, error); + if (!treebootserial_target) + return FALSE; + + const char *deploy_basename = glnx_basename (treebootserial_target); + g_autofree char *treecsum = NULL; + int deployserial = -1; + if (!_ostree_sysroot_parse_deploy_path_name (deploy_basename, + &treecsum, &deployserial, error)) + return FALSE; + + glnx_autofd int deployment_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, relative_boot_link, TRUE, + &deployment_dfd, error)) + return FALSE; + + /* See if this is the booted deployment */ + const gboolean looking_for_booted_deployment = + (self->root_is_ostree_booted && !self->booted_deployment); + gboolean is_booted_deployment = FALSE; + if (looking_for_booted_deployment) + { + struct stat stbuf; + if (!glnx_fstat (deployment_dfd, &stbuf, error)) + return FALSE; + /* A bit ugly, we're assigning to a sysroot-owned variable from deep in + * this parsing code. But eh, if something fails the sysroot state can't + * be relied on anyways. + */ + is_booted_deployment = (stbuf.st_dev == self->root_device && + stbuf.st_ino == self->root_inode); + } + + g_autoptr(OstreeDeployment) ret_deployment + = ostree_deployment_new (-1, osname, treecsum, deployserial, + bootcsum, treebootserial); + if (!load_origin (self, ret_deployment, cancellable, error)) + return FALSE; + + ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_NONE; + g_autofree char *unlocked_development_path = + _ostree_sysroot_get_runstate_path (ret_deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT); + struct stat stbuf; + if (lstat (unlocked_development_path, &stbuf) == 0) + ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT; + else + { + GKeyFile *origin = ostree_deployment_get_origin (ret_deployment); + g_autofree char *existing_unlocked_state = origin ? + g_key_file_get_string (origin, "origin", "unlocked", NULL) : NULL; + + if (g_strcmp0 (existing_unlocked_state, "hotfix") == 0) + { + ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX; + } + /* TODO: warn on unknown unlock types? */ + } + + g_debug ("Deployment %s.%d unlocked=%d", treecsum, deployserial, ret_deployment->unlocked); + + if (is_booted_deployment) + self->booted_deployment = g_object_ref (ret_deployment); + if (out_deployment) + *out_deployment = g_steal_pointer (&ret_deployment); + return TRUE; +} + +/* Given a bootloader config, return the value part of the ostree= kernel + * argument. + */ +static char * +get_ostree_kernel_arg_from_config (OstreeBootconfigParser *config) +{ + const char *options = ostree_bootconfig_parser_get (config, "options"); + if (!options) + return NULL; + + g_auto(GStrv) opts = g_strsplit (options, " ", -1); + for (char **iter = opts; *iter; iter++) + { + const char *opt = *iter; + if (g_str_has_prefix (opt, "ostree=")) + return g_strdup (opt + strlen ("ostree=")); + } + + return NULL; +} + +static gboolean +list_deployments_process_one_boot_entry (OstreeSysroot *self, + OstreeBootconfigParser *config, + GPtrArray *inout_deployments, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *ostree_arg = get_ostree_kernel_arg_from_config (config); + if (ostree_arg == NULL) + return glnx_throw (error, "No ostree= kernel argument found"); + + g_autoptr(OstreeDeployment) deployment = NULL; + if (!parse_deployment (self, ostree_arg, &deployment, + cancellable, error)) + return FALSE; + + ostree_deployment_set_bootconfig (deployment, config); + + g_ptr_array_add (inout_deployments, g_object_ref (deployment)); + return TRUE; +} + +static gint +compare_deployments_by_boot_loader_version_reversed (gconstpointer a_pp, + gconstpointer b_pp) +{ + OstreeDeployment *a = *((OstreeDeployment**)a_pp); + OstreeDeployment *b = *((OstreeDeployment**)b_pp); + OstreeBootconfigParser *a_bootconfig = ostree_deployment_get_bootconfig (a); + OstreeBootconfigParser *b_bootconfig = ostree_deployment_get_bootconfig (b); + + /* Staged deployments are always first */ + if (ostree_deployment_is_staged (a)) + { + g_assert (!ostree_deployment_is_staged (b)); + return -1; + } + else if (ostree_deployment_is_staged (b)) + return 1; + + return compare_boot_loader_configs (a_bootconfig, b_bootconfig); +} + +/** + * ostree_sysroot_load: + * @self: Sysroot + * @cancellable: Cancellable + * @error: Error + * + * Load deployment list, bootversion, and subbootversion from the + * rootfs @self. + */ +gboolean +ostree_sysroot_load (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + return ostree_sysroot_load_if_changed (self, NULL, cancellable, error); +} + +static gboolean +ensure_repo (OstreeSysroot *self, + GError **error) +{ + if (self->repo != NULL) + return TRUE; + if (!ensure_sysroot_fd (self, error)) + return FALSE; + self->repo = ostree_repo_open_at (self->sysroot_fd, "ostree/repo", NULL, error); + if (!self->repo) + return FALSE; + + /* Flag it as having been created via ostree_sysroot_get_repo(), and hold a + * weak ref for the remote-add handling. + */ + g_weak_ref_init (&self->repo->sysroot, self); + self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT; + + /* Reload the repo config in case any defaults depend on knowing if this is + * a system repo. + */ + if (!ostree_repo_reload_config (self->repo, NULL, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_initialize: + * @self: sysroot + * + * Subset of ostree_sysroot_load(); performs basic initialization. Notably, one + * can invoke `ostree_sysroot_get_fd()` after calling this function. + * + * It is not necessary to call this function if ostree_sysroot_load() is + * invoked. + * + * Since: 2020.1 + */ +gboolean +ostree_sysroot_initialize (OstreeSysroot *self, + GError **error) +{ + if (!ensure_sysroot_fd (self, error)) + return FALSE; + + if (self->loadstate < OSTREE_SYSROOT_LOAD_STATE_INIT) + { + /* Gather some global state; first if we have the global ostree-booted flag; + * we'll use it to sanity check that we found a booted deployment for example. + * Second, we also find out whether sysroot == /. + */ + if (!glnx_fstatat_allow_noent (AT_FDCWD, "/run/ostree-booted", NULL, 0, error)) + return FALSE; + const gboolean ostree_booted = (errno == 0); + + { struct stat root_stbuf; + if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error)) + return FALSE; + self->root_device = root_stbuf.st_dev; + self->root_inode = root_stbuf.st_ino; + } + + struct stat self_stbuf; + if (!glnx_fstatat (AT_FDCWD, gs_file_get_path_cached (self->path), &self_stbuf, 0, error)) + return FALSE; + + const gboolean root_is_sysroot = + (self->root_device == self_stbuf.st_dev && + self->root_inode == self_stbuf.st_ino); + + self->root_is_ostree_booted = (ostree_booted && root_is_sysroot); + self->loadstate = OSTREE_SYSROOT_LOAD_STATE_INIT; + } + + return TRUE; +} + +/* Reload the staged deployment from the file in /run */ +gboolean +_ostree_sysroot_reload_staged (OstreeSysroot *self, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("Loading staged deployment", error); + if (!self->root_is_ostree_booted) + return TRUE; /* Note early return */ + + g_assert (self->booted_deployment); + + g_clear_object (&self->staged_deployment); + g_clear_pointer (&self->staged_deployment_data, (GDestroyNotify)g_variant_unref); + + /* Read the staged state from disk */ + glnx_autofd int fd = -1; + if (!ot_openat_ignore_enoent (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, &fd, error)) + return FALSE; + if (fd != -1) + { + g_autoptr(GBytes) contents = ot_fd_readall_or_mmap (fd, 0, error); + if (!contents) + return FALSE; + g_autoptr(GVariant) staged_deployment_data = + g_variant_new_from_bytes ((GVariantType*)"a{sv}", contents, TRUE); + g_autoptr(GVariantDict) staged_deployment_dict = + g_variant_dict_new (staged_deployment_data); + + /* Parse it */ + g_autoptr(GVariant) target = NULL; + g_autofree char **kargs = NULL; + g_variant_dict_lookup (staged_deployment_dict, "target", "@a{sv}", &target); + g_variant_dict_lookup (staged_deployment_dict, "kargs", "^a&s", &kargs); + if (target) + { + g_autoptr(OstreeDeployment) staged = + _ostree_sysroot_deserialize_deployment_from_variant (target, error); + if (!staged) + return FALSE; + + _ostree_deployment_set_bootconfig_from_kargs (staged, kargs); + if (!load_origin (self, staged, NULL, error)) + return FALSE; + + self->staged_deployment = g_steal_pointer (&staged); + self->staged_deployment_data = g_steal_pointer (&staged_deployment_data); + /* We set this flag for ostree_deployment_is_staged() because that API + * doesn't have access to the sysroot, which currently has the + * canonical "staged_deployment" reference. + */ + self->staged_deployment->staged = TRUE; + } + } + + return TRUE; +} + +static gboolean +sysroot_load_from_bootloader_configs (OstreeSysroot *self, + GCancellable *cancellable, + GError **error) +{ + struct stat stbuf; + + int bootversion = 0; + if (!read_current_bootversion (self, &bootversion, cancellable, error)) + return FALSE; + + int subbootversion = 0; + if (!_ostree_sysroot_read_current_subbootversion (self, bootversion, &subbootversion, + cancellable, error)) + return FALSE; + + g_autoptr(GPtrArray) boot_loader_configs = NULL; + if (!_ostree_sysroot_read_boot_loader_configs (self, bootversion, &boot_loader_configs, + cancellable, error)) + return FALSE; + + g_autoptr(GPtrArray) deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + + g_assert (boot_loader_configs); /* Pacify static analysis */ + for (guint i = 0; i < boot_loader_configs->len; i++) + { + OstreeBootconfigParser *config = boot_loader_configs->pdata[i]; + + /* Note this also sets self->booted_deployment */ + if (!list_deployments_process_one_boot_entry (self, config, deployments, + cancellable, error)) + { + g_clear_object (&self->booted_deployment); + return FALSE; + } + } + + if (self->root_is_ostree_booted && !self->booted_deployment) + { + if (!glnx_fstatat_allow_noent (self->sysroot_fd, "boot/loader", NULL, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == ENOENT) + { + return glnx_throw (error, "Unexpected state: /run/ostree-booted found, but no /boot/loader directory"); + } + else + { + return glnx_throw (error, "Unexpected state: /run/ostree-booted found and in / sysroot, but bootloader entry not found"); + } + } + + if (!_ostree_sysroot_reload_staged (self, error)) + return FALSE; + + /* Ensure the entires are sorted */ + g_ptr_array_sort (deployments, compare_deployments_by_boot_loader_version_reversed); + + /* Staged shows up first */ + if (self->staged_deployment) + g_ptr_array_insert (deployments, 0, g_object_ref (self->staged_deployment)); + + /* And then set their index variables */ + for (guint i = 0; i < deployments->len; i++) + { + OstreeDeployment *deployment = deployments->pdata[i]; + ostree_deployment_set_index (deployment, i); + } + + /* Determine whether we're "physical" or not, the first time we load deployments */ + if (self->loadstate < OSTREE_SYSROOT_LOAD_STATE_LOADED) + { + /* If we have a booted deployment, the sysroot is / and we're definitely + * not physical. + */ + if (self->booted_deployment) + self->is_physical = FALSE; /* (the default, but explicit for clarity) */ + /* Otherwise - check for /sysroot which should only exist in a deployment, + * not in ${sysroot} (a metavariable for the real physical root). + */ + else + { + if (!glnx_fstatat_allow_noent (self->sysroot_fd, "sysroot", &stbuf, 0, error)) + return FALSE; + if (errno == ENOENT) + self->is_physical = TRUE; + } + /* Otherwise, the default is FALSE */ + + self->loadstate = OSTREE_SYSROOT_LOAD_STATE_LOADED; + } + + self->bootversion = bootversion; + self->subbootversion = subbootversion; + self->deployments = g_steal_pointer (&deployments); + + return TRUE; +} + +/** + * ostree_sysroot_load_if_changed: + * @self: #OstreeSysroot + * @out_changed: (out caller-allocates): + * @cancellable: Cancellable + * @error: Error + * + * Since: 2016.4 + */ +gboolean +ostree_sysroot_load_if_changed (OstreeSysroot *self, + gboolean *out_changed, + GCancellable *cancellable, + GError **error) +{ + GLNX_AUTO_PREFIX_ERROR ("loading sysroot", error); + + if (!ostree_sysroot_initialize (self, error)) + return FALSE; + + /* Here we also lazily initialize the repository. We didn't do this + * previous to v2017.6, but we do now to support the error-free + * ostree_sysroot_repo() API. + */ + if (!ensure_repo (self, error)) + return FALSE; + + struct stat stbuf; + if (!glnx_fstatat (self->sysroot_fd, "ostree/deploy", &stbuf, 0, error)) + return FALSE; + + if (self->loaded_ts.tv_sec == stbuf.st_mtim.tv_sec && + self->loaded_ts.tv_nsec == stbuf.st_mtim.tv_nsec) + { + if (out_changed) + *out_changed = FALSE; + /* Note early return */ + return TRUE; + } + + g_clear_pointer (&self->deployments, g_ptr_array_unref); + g_clear_object (&self->booted_deployment); + g_clear_object (&self->staged_deployment); + self->bootversion = -1; + self->subbootversion = -1; + + if (!sysroot_load_from_bootloader_configs (self, cancellable, error)) + return FALSE; + + self->loaded_ts = stbuf.st_mtim; + + if (out_changed) + *out_changed = TRUE; + return TRUE; +} + +int +ostree_sysroot_get_bootversion (OstreeSysroot *self) +{ + return self->bootversion; +} + +int +ostree_sysroot_get_subbootversion (OstreeSysroot *self) +{ + return self->subbootversion; +} + +/** + * ostree_sysroot_get_booted_deployment: + * @self: Sysroot + * + * Returns: (transfer none): The currently booted deployment, or %NULL if none + */ +OstreeDeployment * +ostree_sysroot_get_booted_deployment (OstreeSysroot *self) +{ + g_return_val_if_fail (self->loadstate == OSTREE_SYSROOT_LOAD_STATE_LOADED, NULL); + + return self->booted_deployment; +} + +/** + * ostree_sysroot_get_staged_deployment: + * @self: Sysroot + * + * Returns: (transfer none): The currently staged deployment, or %NULL if none + * + * Since: 2018.5 + */ +OstreeDeployment * +ostree_sysroot_get_staged_deployment (OstreeSysroot *self) +{ + g_return_val_if_fail (self->loadstate == OSTREE_SYSROOT_LOAD_STATE_LOADED, NULL); + + return self->staged_deployment; +} + +/** + * ostree_sysroot_get_deployments: + * @self: Sysroot + * + * Returns: (element-type OstreeDeployment) (transfer container): Ordered list of deployments + */ +GPtrArray * +ostree_sysroot_get_deployments (OstreeSysroot *self) +{ + g_return_val_if_fail (self->loadstate == OSTREE_SYSROOT_LOAD_STATE_LOADED, NULL); + + GPtrArray *copy = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + for (guint i = 0; i < self->deployments->len; i++) + g_ptr_array_add (copy, g_object_ref (self->deployments->pdata[i])); + return copy; +} + +/** + * ostree_sysroot_get_deployment_dirpath: + * @self: Repo + * @deployment: A deployment + * + * Note this function only returns a *relative* path - if you want + * to access, it, you must either use fd-relative api such as openat(), + * or concatenate it with the full ostree_sysroot_get_path(). + * + * Returns: (transfer full): Path to deployment root directory, relative to sysroot + */ +char * +ostree_sysroot_get_deployment_dirpath (OstreeSysroot *self, + OstreeDeployment *deployment) +{ + return g_strdup_printf ("ostree/deploy/%s/deploy/%s.%d", + ostree_deployment_get_osname (deployment), + ostree_deployment_get_csum (deployment), + ostree_deployment_get_deployserial (deployment)); +} + +/** + * ostree_sysroot_get_deployment_directory: + * @self: Sysroot + * @deployment: A deployment + * + * Returns: (transfer full): Path to deployment root directory + */ +GFile * +ostree_sysroot_get_deployment_directory (OstreeSysroot *self, + OstreeDeployment *deployment) +{ + g_autofree char *dirpath = ostree_sysroot_get_deployment_dirpath (self, deployment); + return g_file_resolve_relative_path (self->path, dirpath); +} + +/** + * ostree_sysroot_get_deployment_origin_path: + * @deployment_path: A deployment path + * + * Returns: (transfer full): Path to deployment origin file + */ +GFile * +ostree_sysroot_get_deployment_origin_path (GFile *deployment_path) +{ + g_autoptr(GFile) deployment_parent = g_file_get_parent (deployment_path); + return ot_gfile_resolve_path_printf (deployment_parent, + "%s.origin", + gs_file_get_path_cached (deployment_path)); +} + +/** + * ostree_sysroot_get_repo: + * @self: Sysroot + * @out_repo: (out) (transfer full) (optional): Repository in sysroot @self + * @cancellable: Cancellable + * @error: Error + * + * Retrieve the OSTree repository in sysroot @self. The repo is guaranteed to be open + * (see ostree_repo_open()). + * + * Returns: %TRUE on success, %FALSE otherwise + */ +gboolean +ostree_sysroot_get_repo (OstreeSysroot *self, + OstreeRepo **out_repo, + GCancellable *cancellable, + GError **error) +{ + if (!ensure_repo (self, error)) + return FALSE; + if (out_repo != NULL) + *out_repo = g_object_ref (self->repo); + return TRUE; +} + +/** + * ostree_sysroot_repo: + * @self: Sysroot + * + * This function is a variant of ostree_sysroot_get_repo() that cannot fail, and + * returns a cached repository. Can only be called after ostree_sysroot_initialize() + * or ostree_sysroot_load() has been invoked successfully. + * + * Returns: (transfer none): The OSTree repository in sysroot @self. + * + * Since: 2017.7 + */ +OstreeRepo * +ostree_sysroot_repo (OstreeSysroot *self) +{ + g_return_val_if_fail (self->loadstate >= OSTREE_SYSROOT_LOAD_STATE_LOADED, NULL); + g_assert (self->repo); + return self->repo; +} + +/** + * ostree_sysroot_query_bootloader: + * @sysroot: Sysroot + * @out_bootloader: (out) (transfer full) (allow-none): Return location for bootloader, may be %NULL + * @cancellable: Cancellable + * @error: Error + */ +gboolean +_ostree_sysroot_query_bootloader (OstreeSysroot *sysroot, + OstreeBootloader **out_bootloader, + GCancellable *cancellable, + GError **error) +{ + gboolean is_active; + g_autoptr(OstreeBootloader) ret_loader = + (OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot); + if (!_ostree_bootloader_query (ret_loader, &is_active, + cancellable, error)) + return FALSE; + + if (!is_active) + { + g_object_unref (ret_loader); + ret_loader = (OstreeBootloader*)_ostree_bootloader_grub2_new (sysroot); + if (!_ostree_bootloader_query (ret_loader, &is_active, + cancellable, error)) + return FALSE; + } + if (!is_active) + { + g_object_unref (ret_loader); + ret_loader = (OstreeBootloader*)_ostree_bootloader_uboot_new (sysroot); + if (!_ostree_bootloader_query (ret_loader, &is_active, cancellable, error)) + return FALSE; + } + if (!is_active) + g_clear_object (&ret_loader); + + ot_transfer_out_value(out_bootloader, &ret_loader); + return TRUE; +} + +char * +_ostree_sysroot_join_lines (GPtrArray *lines) +{ + GString *buf = g_string_new (""); + gboolean prev_was_empty = FALSE; + + for (guint i = 0; i < lines->len; i++) + { + const char *line = lines->pdata[i]; + /* Special bit to remove extraneous empty lines */ + if (*line == '\0') + { + if (prev_was_empty || i == 0) + continue; + else + prev_was_empty = TRUE; + } + g_string_append (buf, line); + g_string_append_c (buf, '\n'); + } + return g_string_free (buf, FALSE); +} + +/** + * ostree_sysroot_query_deployments_for: + * @self: Sysroot + * @osname: (allow-none): "stateroot" name + * @out_pending: (out) (allow-none) (transfer full): The pending deployment + * @out_rollback: (out) (allow-none) (transfer full): The rollback deployment + * + * Find the pending and rollback deployments for @osname. Pass %NULL for @osname + * to use the booted deployment's osname. By default, pending deployment is the + * first deployment in the order that matches @osname, and @rollback will be the + * next one after the booted deployment, or the deployment after the pending if + * we're not looking at the booted deployment. + * + * Since: 2017.7 + */ +void +ostree_sysroot_query_deployments_for (OstreeSysroot *self, + const char *osname, + OstreeDeployment **out_pending, + OstreeDeployment **out_rollback) +{ + g_return_if_fail (osname != NULL || self->booted_deployment != NULL); + g_autoptr(OstreeDeployment) ret_pending = NULL; + g_autoptr(OstreeDeployment) ret_rollback = NULL; + + if (osname == NULL) + osname = ostree_deployment_get_osname (self->booted_deployment); + + gboolean found_booted = FALSE; + for (guint i = 0; i < self->deployments->len; i++) + { + OstreeDeployment *deployment = self->deployments->pdata[i]; + + /* Ignore deployments not for this osname */ + if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0) + continue; + + /* Is this deployment booted? If so, note we're past the booted */ + if (self->booted_deployment != NULL && + ostree_deployment_equal (deployment, self->booted_deployment)) + { + found_booted = TRUE; + continue; + } + + if (!found_booted && !ret_pending) + ret_pending = g_object_ref (deployment); + else if (found_booted && !ret_rollback) + ret_rollback = g_object_ref (deployment); + } + if (out_pending) + *out_pending = g_steal_pointer (&ret_pending); + if (out_rollback) + *out_rollback = g_steal_pointer (&ret_rollback); +} + + +/** + * ostree_sysroot_get_merge_deployment: + * @self: Sysroot + * @osname: (allow-none): Operating system group + * + * Find the deployment to use as a configuration merge source; this is + * the first one in the current deployment list which matches osname. + * + * Returns: (transfer full): Configuration merge deployment + */ +OstreeDeployment * +ostree_sysroot_get_merge_deployment (OstreeSysroot *self, + const char *osname) +{ + g_return_val_if_fail (osname != NULL || self->booted_deployment != NULL, NULL); + + if (osname == NULL) + osname = ostree_deployment_get_osname (self->booted_deployment); + + /* If we're booted into the OS into which we're deploying, then + * merge the currently *booted* configuration, rather than the most + * recently deployed. + */ + if (self->booted_deployment && + g_strcmp0 (ostree_deployment_get_osname (self->booted_deployment), osname) == 0) + return g_object_ref (self->booted_deployment); + else + { + g_autoptr(OstreeDeployment) pending = NULL; + ostree_sysroot_query_deployments_for (self, osname, &pending, NULL); + return g_steal_pointer (&pending); + } +} + +/** + * ostree_sysroot_origin_new_from_refspec: + * @self: Sysroot + * @refspec: A refspec + * + * Returns: (transfer full): A new config file which sets @refspec as an origin + */ +GKeyFile * +ostree_sysroot_origin_new_from_refspec (OstreeSysroot *self, + const char *refspec) +{ + GKeyFile *ret = g_key_file_new (); + g_key_file_set_string (ret, "origin", "refspec", refspec); + return ret; +} + +/** + * ostree_sysroot_lock: + * @self: Self + * @error: Error + * + * Acquire an exclusive multi-process write lock for @self. This call + * blocks until the lock has been acquired. The lock is not + * reentrant. + * + * Release the lock with ostree_sysroot_unlock(). The lock will also + * be released if @self is deallocated. + */ +gboolean +ostree_sysroot_lock (OstreeSysroot *self, + GError **error) +{ + if (!ensure_sysroot_fd (self, error)) + return FALSE; + + if (!_ostree_sysroot_ensure_writable (self, error)) + return FALSE; + + return glnx_make_lock_file (self->sysroot_fd, OSTREE_SYSROOT_LOCKFILE, + LOCK_EX, &self->lock, error); +} + +/** + * ostree_sysroot_try_lock: + * @self: Self + * @out_acquired: (out): Whether or not the lock has been acquired + * @error: Error + * + * Try to acquire an exclusive multi-process write lock for @self. If + * another process holds the lock, this function will return + * immediately, setting @out_acquired to %FALSE, and returning %TRUE + * (and no error). + * + * Release the lock with ostree_sysroot_unlock(). The lock will also + * be released if @self is deallocated. + */ +gboolean +ostree_sysroot_try_lock (OstreeSysroot *self, + gboolean *out_acquired, + GError **error) +{ + if (!ensure_sysroot_fd (self, error)) + return FALSE; + + if (!_ostree_sysroot_ensure_writable (self, error)) + return FALSE; + + /* Note use of LOCK_NB */ + g_autoptr(GError) local_error = NULL; + if (!glnx_make_lock_file (self->sysroot_fd, OSTREE_SYSROOT_LOCKFILE, + LOCK_EX | LOCK_NB, &self->lock, &local_error)) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) + { + *out_acquired = FALSE; + } + else + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + else + { + *out_acquired = TRUE; + } + + return TRUE; +} + +/** + * ostree_sysroot_unlock: + * @self: Self + * + * Clear the lock previously acquired with ostree_sysroot_lock(). It + * is safe to call this function if the lock has not been previously + * acquired. + */ +void +ostree_sysroot_unlock (OstreeSysroot *self) +{ + glnx_release_lock_file (&self->lock); +} + +static void +lock_in_thread (GTask *task, + gpointer source, + gpointer task_data, + GCancellable *cancellable) +{ + GError *local_error = NULL; + OstreeSysroot *self = source; + + if (!ostree_sysroot_lock (self, &local_error)) + goto out; + + if (g_cancellable_set_error_if_cancelled (cancellable, &local_error)) + ostree_sysroot_unlock (self); + + out: + if (local_error) + g_task_return_error (task, local_error); + else + g_task_return_boolean (task, TRUE); +} + +/** + * ostree_sysroot_lock_async: + * @self: Self + * @cancellable: Cancellable + * @callback: Callback + * @user_data: User data + * + * An asynchronous version of ostree_sysroot_lock(). + */ +void +ostree_sysroot_lock_async (OstreeSysroot *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, user_data); + g_task_run_in_thread (task, lock_in_thread); +} + +/** + * ostree_sysroot_lock_finish: + * @self: Self + * @result: Result + * @error: Error + * + * Call when ostree_sysroot_lock_async() is ready. + */ +gboolean +ostree_sysroot_lock_finish (OstreeSysroot *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + return g_task_propagate_boolean ((GTask*)result, error); +} + +/** + * ostree_sysroot_init_osname: + * @self: Sysroot + * @osname: Name group of operating system checkouts + * @cancellable: Cancellable + * @error: Error + * + * Initialize the directory structure for an "osname", which is a + * group of operating system deployments, with a shared `/var`. One + * is required for generating a deployment. + * + * Since: 2016.4 + */ +gboolean +ostree_sysroot_init_osname (OstreeSysroot *self, + const char *osname, + GCancellable *cancellable, + GError **error) +{ + if (!_ostree_sysroot_ensure_writable (self, error)) + return FALSE; + + const char *deploydir = glnx_strjoina ("ostree/deploy/", osname); + if (mkdirat (self->sysroot_fd, deploydir, 0777) < 0) + return glnx_throw_errno_prefix (error, "Creating %s", deploydir); + + glnx_autofd int dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, deploydir, TRUE, &dfd, error)) + return FALSE; + + if (mkdirat (dfd, "var", 0777) < 0) + return glnx_throw_errno_prefix (error, "Creating %s", "var"); + + /* This is a bit of a legacy hack...but we have to keep it around + * now. We're ensuring core subdirectories of /var exist. + */ + if (mkdirat (dfd, "var/tmp", 0777) < 0) + return glnx_throw_errno_prefix (error, "Creating %s", "var/tmp"); + + if (fchmodat (dfd, "var/tmp", 01777, 0) < 0) + return glnx_throw_errno_prefix (error, "fchmod %s", "var/tmp"); + + if (mkdirat (dfd, "var/lib", 0777) < 0) + return glnx_throw_errno_prefix (error, "Creating %s", "var/tmp"); + + /* This needs to be available and properly labeled early during the boot + * process (before tmpfiles.d kicks in), so that journald can flush logs from + * the first boot there. https://bugzilla.redhat.com/show_bug.cgi?id=1265295 + * */ + if (mkdirat (dfd, "var/log", 0755) < 0) + return glnx_throw_errno_prefix (error, "Creating %s", "var/log"); + + if (symlinkat ("../run", dfd, "var/run") < 0) + return glnx_throw_errno_prefix (error, "Symlinking %s", "var/run"); + + if (symlinkat ("../run/lock", dfd, "var/lock") < 0) + return glnx_throw_errno_prefix (error, "Symlinking %s", "var/lock"); + + if (!_ostree_sysroot_bump_mtime (self, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_simple_write_deployment: + * @sysroot: Sysroot + * @osname: (allow-none): OS name + * @new_deployment: Prepend this deployment to the list + * @merge_deployment: (allow-none): Use this deployment for configuration merge + * @flags: Flags controlling behavior + * @cancellable: Cancellable + * @error: Error + * + * Prepend @new_deployment to the list of deployments, commit, and + * cleanup. By default, all other deployments for the given @osname + * except the merge deployment and the booted deployment will be + * garbage collected. + * + * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN is + * specified, then all current deployments will be kept. + * + * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING is + * specified, then pending deployments will be kept. + * + * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK is + * specified, then rollback deployments will be kept. + * + * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT is + * specified, then instead of prepending, the new deployment will be + * added right after the booted or merge deployment, instead of first. + * + * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN is + * specified, then no cleanup will be performed after adding the + * deployment. Make sure to call ostree_sysroot_cleanup() sometime + * later, instead. + */ +gboolean +ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, + const char *osname, + OstreeDeployment *new_deployment, + OstreeDeployment *merge_deployment, + OstreeSysrootSimpleWriteDeploymentFlags flags, + GCancellable *cancellable, + GError **error) +{ + const gboolean postclean = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN) == 0; + const gboolean make_default = + !((flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT) > 0); + const gboolean retain_pending = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING) > 0; + const gboolean retain_rollback = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK) > 0; + gboolean retain = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0; + + g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot); + OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + + if (osname == NULL && booted_deployment) + osname = ostree_deployment_get_osname (booted_deployment); + + gboolean added_new = FALSE; + g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); + if (make_default) + { + g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); + added_new = TRUE; + } + + /* without a booted and a merge deployment, retain_pending/rollback become meaningless; + * let's just retain all deployments in that case */ + if (!booted_deployment && !merge_deployment && (retain_pending || retain_rollback)) + retain = TRUE; + + /* tracks when we come across the booted deployment */ + gboolean before_booted = TRUE; + gboolean before_merge = TRUE; + for (guint i = 0; i < deployments->len; i++) + { + OstreeDeployment *deployment = deployments->pdata[i]; + const gboolean osname_matches = + (osname == NULL || g_str_equal (ostree_deployment_get_osname (deployment), osname)); + const gboolean is_booted = ostree_deployment_equal (deployment, booted_deployment); + const gboolean is_merge = ostree_deployment_equal (deployment, merge_deployment); + + if (is_booted) + before_booted = FALSE; + if (is_merge) + before_merge = FALSE; + + /* use the booted deployment as the "crossover" point between pending and rollback + * deployments, fall back on merge deployment */ + const gboolean passed_crossover = booted_deployment ? !before_booted : !before_merge; + + /* Retain deployment if: + * - we're explicitly asked to, or + * - it's pinned + * - the deployment is for another osname, or + * - we're keeping pending deployments and this is a pending deployment, or + * - this is the merge or boot deployment, or + * - we're keeping rollback deployments and this is a rollback deployment + */ + if (retain + || ostree_deployment_is_pinned (deployment) + || !osname_matches + || (retain_pending && !passed_crossover) + || (is_booted || is_merge) + || (retain_rollback && passed_crossover)) + g_ptr_array_add (new_deployments, g_object_ref (deployment)); + + /* add right after booted/merge deployment */ + if (!added_new && passed_crossover) + { + g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); + added_new = TRUE; + } + } + + /* add it last if no crossover defined (or it's the first deployment in the sysroot) */ + if (!added_new) + g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); + + OstreeSysrootWriteDeploymentsOpts write_opts = { .do_postclean = postclean }; + if (!ostree_sysroot_write_deployments_with_options (sysroot, new_deployments, &write_opts, + cancellable, error)) + return FALSE; + + return TRUE; +} + +/* Deploy a copy of @target_deployment */ +static gboolean +clone_deployment (OstreeSysroot *sysroot, + OstreeDeployment *target_deployment, + OstreeDeployment *merge_deployment, + GCancellable *cancellable, + GError **error) +{ + /* Ensure we have a clean slate */ + if (!ostree_sysroot_prepare_cleanup (sysroot, cancellable, error)) + return glnx_prefix_error (error, "Performing initial cleanup"); + + /* Copy the bootloader config options */ + OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment); + g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1); + g_autoptr(OstreeKernelArgs) kargs = ostree_kernel_args_new (); + ostree_kernel_args_append_argv (kargs, previous_args); + + /* Deploy the copy */ + g_autoptr(OstreeDeployment) new_deployment = NULL; + g_auto(GStrv) kargs_strv = ostree_kernel_args_to_strv (kargs); + if (!ostree_sysroot_deploy_tree (sysroot, + ostree_deployment_get_osname (target_deployment), + ostree_deployment_get_csum (target_deployment), + ostree_deployment_get_origin (target_deployment), + merge_deployment, kargs_strv, &new_deployment, + cancellable, error)) + return FALSE; + + /* Hotfixes push the deployment as rollback target, so it shouldn't + * be the default. + */ + if (!ostree_sysroot_simple_write_deployment (sysroot, ostree_deployment_get_osname (target_deployment), + new_deployment, merge_deployment, + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT, + cancellable, error)) + return FALSE; + + return TRUE; +} + +/* Do `mkdir()` followed by `chmod()` immediately afterwards to ensure `umask()` isn't + * masking permissions where we don't want it to. Thus we avoid calling `umask()`, which + * would affect the whole process. */ +static gboolean mkdir_unmasked (int dfd, + const char *path, + int mode, + GCancellable *cancellable, + GError **error) +{ + if (!glnx_shutil_mkdir_p_at (dfd, path, mode, cancellable, error)) + return FALSE; + if (fchmodat (dfd, path, mode, 0) < 0) + return glnx_throw_errno_prefix (error, "chmod(%s)", path); + return TRUE; +} + +/** + * ostree_sysroot_deployment_unlock: + * @self: Sysroot + * @deployment: Deployment + * @unlocked_state: Transition to this unlocked state + * @cancellable: Cancellable + * @error: Error + * + * Configure the target deployment @deployment such that it + * is writable. There are multiple modes, essentially differing + * in whether or not any changes persist across reboot. + * + * The `OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX` state is persistent + * across reboots. + * + * Since: 2016.4 + */ +gboolean +ostree_sysroot_deployment_unlock (OstreeSysroot *self, + OstreeDeployment *deployment, + OstreeDeploymentUnlockedState unlocked_state, + GCancellable *cancellable, + GError **error) +{ + /* This function cannot re-lock */ + g_return_val_if_fail (unlocked_state != OSTREE_DEPLOYMENT_UNLOCKED_NONE, FALSE); + + OstreeDeploymentUnlockedState current_unlocked = ostree_deployment_get_unlocked (deployment); + if (current_unlocked != OSTREE_DEPLOYMENT_UNLOCKED_NONE) + return glnx_throw (error, "Deployment is already in unlocked state: %s", + ostree_deployment_unlocked_state_to_string (current_unlocked)); + + g_autoptr(OstreeDeployment) merge_deployment = + ostree_sysroot_get_merge_deployment (self, ostree_deployment_get_osname (deployment)); + if (!merge_deployment) + return glnx_throw (error, "No previous deployment to duplicate"); + + /* For hotfixes, we push a rollback target */ + if (unlocked_state == OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX) + { + if (!clone_deployment (self, deployment, merge_deployment, cancellable, error)) + return FALSE; + } + + /* Crack it open */ + if (!ostree_sysroot_deployment_set_mutable (self, deployment, TRUE, + cancellable, error)) + return FALSE; + + g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); + glnx_autofd int deployment_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error)) + return FALSE; + + g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error); + if (!sepolicy) + return FALSE; + + /* we want our /usr overlay to have the same permission bits as the one we'll shadow */ + mode_t usr_mode; + { struct stat stbuf; + if (!glnx_fstatat (deployment_dfd, "usr", &stbuf, 0, error)) + return FALSE; + usr_mode = stbuf.st_mode; + } + + const char *ovl_options = NULL; + static const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work"; + switch (unlocked_state) + { + case OSTREE_DEPLOYMENT_UNLOCKED_NONE: + g_assert_not_reached (); + break; + case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX: + { + /* Create the overlayfs directories in the deployment root + * directly for hotfixes. The ostree-prepare-root.c helper + * is also set up to detect and mount these. + */ + if (!mkdir_unmasked (deployment_dfd, ".usr-ovl-upper", usr_mode, cancellable, error)) + return FALSE; + if (!mkdir_unmasked (deployment_dfd, ".usr-ovl-work", usr_mode, cancellable, error)) + return FALSE; + ovl_options = hotfix_ovl_options; + } + break; + case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT: + { + /* We're just doing transient development/hacking? Okay, + * stick the overlayfs bits in /var/tmp. + */ + char *development_ovldir = strdupa ("/var/tmp/ostree-unlock-ovl.XXXXXX"); + const char *development_ovl_upper; + const char *development_ovl_work; + + /* Ensure that the directory is created with the same label as `/usr` */ + { g_auto(OstreeSepolicyFsCreatecon) con = { 0, }; + + if (!_ostree_sepolicy_preparefscreatecon (&con, sepolicy, + "/usr", usr_mode, error)) + return FALSE; + + if (g_mkdtemp_full (development_ovldir, 0755) == NULL) + return glnx_throw_errno_prefix (error, "mkdtemp"); + } + + development_ovl_upper = glnx_strjoina (development_ovldir, "/upper"); + if (!mkdir_unmasked (AT_FDCWD, development_ovl_upper, usr_mode, cancellable, error)) + return FALSE; + development_ovl_work = glnx_strjoina (development_ovldir, "/work"); + if (!mkdir_unmasked (AT_FDCWD, development_ovl_work, usr_mode, cancellable, error)) + return FALSE; + ovl_options = glnx_strjoina ("lowerdir=usr,upperdir=", development_ovl_upper, + ",workdir=", development_ovl_work); + } + } + + g_assert (ovl_options != NULL); + + /* Here we run `mount()` in a fork()ed child because we need to use + * `chdir()` in order to have the mount path options to overlayfs not + * look ugly. + * + * We can't `chdir()` inside a shared library since there may be + * threads, etc. + */ + { + pid_t mount_child = fork (); + if (mount_child < 0) + return glnx_throw_errno_prefix (error, "fork"); + else if (mount_child == 0) + { + /* Child process. Do NOT use any GLib API here; it's not generally fork() safe. + * + * TODO: report errors across a pipe (or use the journal?) rather than + * spewing to stderr. + */ + if (fchdir (deployment_dfd) < 0) + err (1, "fchdir"); + if (mount ("overlay", "/usr", "overlay", 0, ovl_options) < 0) + err (1, "mount"); + exit (EXIT_SUCCESS); + } + else + { + /* Parent */ + int estatus; + + if (TEMP_FAILURE_RETRY (waitpid (mount_child, &estatus, 0)) < 0) + return glnx_throw_errno_prefix (error, "waitpid() on mount helper"); + if (!g_spawn_check_exit_status (estatus, error)) + return glnx_prefix_error (error, "Failed overlayfs mount"); + } + } + + g_autoptr(OstreeDeployment) deployment_clone = ostree_deployment_clone (deployment); + GKeyFile *origin_clone = ostree_deployment_get_origin (deployment_clone); + + /* Now, write out the flag saying what we did */ + switch (unlocked_state) + { + case OSTREE_DEPLOYMENT_UNLOCKED_NONE: + g_assert_not_reached (); + break; + case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX: + g_key_file_set_string (origin_clone, "origin", "unlocked", + ostree_deployment_unlocked_state_to_string (unlocked_state)); + if (!ostree_sysroot_write_origin_file (self, deployment, origin_clone, + cancellable, error)) + return FALSE; + break; + case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT: + { + g_autofree char *devpath = + _ostree_sysroot_get_runstate_path (deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT); + g_autofree char *devpath_parent = dirname (g_strdup (devpath)); + + if (!glnx_shutil_mkdir_p_at (AT_FDCWD, devpath_parent, 0755, cancellable, error)) + return FALSE; + + if (!g_file_set_contents (devpath, "", 0, error)) + return FALSE; + } + } + + /* For hotfixes we already pushed a rollback which will bump the + * mtime, but we need to bump it again so that clients get the state + * change for this deployment. For development we need to do this + * regardless. + */ + if (!_ostree_sysroot_bump_mtime (self, error)) + return FALSE; + + return TRUE; +} + +/** + * ostree_sysroot_deployment_set_pinned: + * @self: Sysroot + * @deployment: A deployment + * @is_pinned: Whether or not deployment will be automatically GC'd + * @error: Error + * + * By default, deployments may be subject to garbage collection. Typical uses of + * libostree only retain at most 2 deployments. If @is_pinned is `TRUE`, a + * metadata bit will be set causing libostree to avoid automatic GC of the + * deployment. However, this is really an "advisory" note; it's still possible + * for e.g. older versions of libostree unaware of pinning to GC the deployment. + * + * This function does nothing and returns successfully if the deployment + * is already in the desired pinning state. It is an error to try to pin + * the staged deployment (as it's not in the bootloader entries). + * + * Since: 2018.3 + */ +gboolean +ostree_sysroot_deployment_set_pinned (OstreeSysroot *self, + OstreeDeployment *deployment, + gboolean is_pinned, + GError **error) +{ + const gboolean current_pin = ostree_deployment_is_pinned (deployment); + if (is_pinned == current_pin) + return TRUE; + + if (ostree_deployment_is_staged (deployment)) + return glnx_throw (error, "Cannot pin staged deployment"); + + g_autoptr(OstreeDeployment) deployment_clone = ostree_deployment_clone (deployment); + GKeyFile *origin_clone = ostree_deployment_get_origin (deployment_clone); + + if (is_pinned) + g_key_file_set_boolean (origin_clone, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", TRUE); + else + g_key_file_remove_key (origin_clone, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", NULL); + + if (!ostree_sysroot_write_origin_file (self, deployment, origin_clone, NULL, error)) + return FALSE; + + return TRUE; +} diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h new file mode 100644 index 0000000..d9f5a54 --- /dev/null +++ b/src/libostree/ostree-sysroot.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ostree-repo.h" +#include "ostree-deployment.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_SYSROOT ostree_sysroot_get_type() +#define OSTREE_SYSROOT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_SYSROOT, OstreeSysroot)) +#define OSTREE_IS_SYSROOT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_SYSROOT)) + +_OSTREE_PUBLIC +GType ostree_sysroot_get_type (void); + +_OSTREE_PUBLIC +OstreeSysroot* ostree_sysroot_new (GFile *path); + +_OSTREE_PUBLIC +OstreeSysroot* ostree_sysroot_new_default (void); + +_OSTREE_PUBLIC +void ostree_sysroot_set_mount_namespace_in_use (OstreeSysroot *self); + +_OSTREE_PUBLIC +GFile *ostree_sysroot_get_path (OstreeSysroot *self); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_is_booted (OstreeSysroot *self); + +_OSTREE_PUBLIC +int ostree_sysroot_get_fd (OstreeSysroot *self); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_initialize (OstreeSysroot *self, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_load (OstreeSysroot *self, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_load_if_changed (OstreeSysroot *self, + gboolean *out_changed, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_sysroot_unload (OstreeSysroot *self); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_ensure_initialized (OstreeSysroot *self, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +int ostree_sysroot_get_bootversion (OstreeSysroot *self); +_OSTREE_PUBLIC +int ostree_sysroot_get_subbootversion (OstreeSysroot *self); +_OSTREE_PUBLIC +GPtrArray *ostree_sysroot_get_deployments (OstreeSysroot *self); +_OSTREE_PUBLIC +OstreeDeployment *ostree_sysroot_get_booted_deployment (OstreeSysroot *self); +_OSTREE_PUBLIC +OstreeDeployment *ostree_sysroot_get_staged_deployment (OstreeSysroot *self); + +_OSTREE_PUBLIC +GFile *ostree_sysroot_get_deployment_directory (OstreeSysroot *self, + OstreeDeployment *deployment); + +_OSTREE_PUBLIC +char *ostree_sysroot_get_deployment_dirpath (OstreeSysroot *self, + OstreeDeployment *deployment); + +_OSTREE_PUBLIC +GFile * ostree_sysroot_get_deployment_origin_path (GFile *deployment_path); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_lock (OstreeSysroot *self, GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_try_lock (OstreeSysroot *self, + gboolean *out_acquired, + GError **error); +_OSTREE_PUBLIC +void ostree_sysroot_lock_async (OstreeSysroot *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +_OSTREE_PUBLIC +gboolean ostree_sysroot_lock_finish (OstreeSysroot *self, + GAsyncResult *result, + GError **error); +_OSTREE_PUBLIC +void ostree_sysroot_unlock (OstreeSysroot *self); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_init_osname (OstreeSysroot *self, + const char *osname, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_cleanup (OstreeSysroot *self, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_prepare_cleanup (OstreeSysroot *self, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean +ostree_sysroot_cleanup_prune_repo (OstreeSysroot *sysroot, + OstreeRepoPruneOptions *options, + gint *out_objects_total, + gint *out_objects_pruned, + guint64 *out_pruned_object_size_total, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_write_origin_file (OstreeSysroot *sysroot, + OstreeDeployment *deployment, + GKeyFile *new_origin, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +OstreeRepo * ostree_sysroot_repo (OstreeSysroot *self); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_get_repo (OstreeSysroot *self, + OstreeRepo **out_repo, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_deployment_set_kargs (OstreeSysroot *self, + OstreeDeployment *deployment, + char **new_kargs, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_write_deployments (OstreeSysroot *self, + GPtrArray *new_deployments, + GCancellable *cancellable, + GError **error); + +typedef struct { + gboolean do_postclean; + gboolean unused_bools[7]; + int unused_ints[7]; + gpointer unused_ptrs[7]; +} OstreeSysrootWriteDeploymentsOpts; + +_OSTREE_PUBLIC +gboolean ostree_sysroot_write_deployments_with_options (OstreeSysroot *self, + GPtrArray *new_deployments, + OstreeSysrootWriteDeploymentsOpts *opts, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_deploy_tree (OstreeSysroot *self, + const char *osname, + const char *revision, + GKeyFile *origin, + OstreeDeployment *provided_merge_deployment, + char **override_kernel_argv, + OstreeDeployment **out_new_deployment, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_stage_tree (OstreeSysroot *self, + const char *osname, + const char *revision, + GKeyFile *origin, + OstreeDeployment *merge_deployment, + char **override_kernel_argv, + OstreeDeployment **out_new_deployment, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_deployment_set_mutable (OstreeSysroot *self, + OstreeDeployment *deployment, + gboolean is_mutable, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_deployment_set_pinned (OstreeSysroot *self, + OstreeDeployment *deployment, + gboolean is_pinned, + GError **error); + +_OSTREE_PUBLIC +gboolean ostree_sysroot_deployment_unlock (OstreeSysroot *self, + OstreeDeployment *deployment, + OstreeDeploymentUnlockedState unlocked_state, + GCancellable *cancellable, + GError **error); + +_OSTREE_PUBLIC +void ostree_sysroot_query_deployments_for (OstreeSysroot *self, + const char *osname, + OstreeDeployment **out_pending, + OstreeDeployment **out_rollback); + +_OSTREE_PUBLIC +OstreeDeployment *ostree_sysroot_get_merge_deployment (OstreeSysroot *self, + const char *osname); + + +_OSTREE_PUBLIC +GKeyFile *ostree_sysroot_origin_new_from_refspec (OstreeSysroot *self, + const char *refspec); + +typedef enum { + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NONE = 0, + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN = (1 << 0), + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT = (1 << 1), + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN = (1 << 2), + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING = (1 << 3), + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK = (1 << 4), +} OstreeSysrootSimpleWriteDeploymentFlags; + +_OSTREE_PUBLIC +gboolean ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, + const char *osname, + OstreeDeployment *new_deployment, + OstreeDeployment *merge_deployment, + OstreeSysrootSimpleWriteDeploymentFlags flags, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/src/libostree/ostree-tls-cert-interaction.c b/src/libostree/ostree-tls-cert-interaction.c new file mode 100644 index 0000000..bd90166 --- /dev/null +++ b/src/libostree/ostree-tls-cert-interaction.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "config.h" + +#include "ostree-tls-cert-interaction.h" + +struct _OstreeTlsCertInteraction +{ + GTlsInteraction parent_instance; + + char *cert_path; + char *key_path; + GTlsCertificate *cert; +}; + +struct _OstreeTlsCertInteractionClass +{ + GTlsInteractionClass parent_class; +}; + +#include + +G_DEFINE_TYPE (OstreeTlsCertInteraction, _ostree_tls_cert_interaction, G_TYPE_TLS_INTERACTION); + +static GTlsInteractionResult +request_certificate (GTlsInteraction *interaction, + GTlsConnection *connection, + GTlsCertificateRequestFlags flags, + GCancellable *cancellable, + GError **error) +{ + OstreeTlsCertInteraction *self = (OstreeTlsCertInteraction*)interaction; + + if (!self->cert) + { + self->cert = g_tls_certificate_new_from_files (self->cert_path, self->key_path, error); + if (!self->cert) + return G_TLS_INTERACTION_FAILED; + } + + g_tls_connection_set_certificate (connection, self->cert); + return G_TLS_INTERACTION_HANDLED; +} + +static void +_ostree_tls_cert_interaction_init (OstreeTlsCertInteraction *interaction) +{ +} + +static void +_ostree_tls_cert_interaction_class_init (OstreeTlsCertInteractionClass *klass) +{ + GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass); + interaction_class->request_certificate = request_certificate; +} + +OstreeTlsCertInteraction * +_ostree_tls_cert_interaction_new (const char *cert_path, + const char *key_path) +{ + OstreeTlsCertInteraction *self = g_object_new (OSTREE_TYPE_TLS_CERT_INTERACTION, NULL); + self->cert_path = g_strdup (cert_path); + self->key_path = g_strdup (key_path); + return self; +} diff --git a/src/libostree/ostree-tls-cert-interaction.h b/src/libostree/ostree-tls-cert-interaction.h new file mode 100644 index 0000000..58db65a --- /dev/null +++ b/src/libostree/ostree-tls-cert-interaction.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#pragma once + +#include "otutil.h" +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_TLS_CERT_INTERACTION (_ostree_tls_cert_interaction_get_type ()) +#define OSTREE_TLS_CERT_INTERACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_TLS_CERT_INTERACTION, OstreeTlsCertInteraction)) +#define OSTREE_TLS_CERT_INTERACTION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_TLS_CERT_INTERACTION, OstreeTlsCertInteractionClass)) +#define OSTREE_IS_TLS_CERT_INTERACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_TLS_CERT_INTERACTION)) +#define OSTREE_IS_TLS_CERT_INTERACTION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_TLS_CERT_INTERACTION)) +#define OSTREE_TLS_CERT_INTERACTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_TLS_CERT_INTERACTION, OstreeTlsCertInteractionClass)) + +typedef struct _OstreeTlsCertInteraction OstreeTlsCertInteraction; +typedef struct _OstreeTlsCertInteractionClass OstreeTlsCertInteractionClass; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeTlsCertInteraction, g_object_unref) + +GType _ostree_tls_cert_interaction_get_type (void) G_GNUC_CONST; + +OstreeTlsCertInteraction * _ostree_tls_cert_interaction_new (const char *cert_path, + const char *key_path); + +G_END_DECLS diff --git a/src/libostree/ostree-types.h b/src/libostree/ostree-types.h new file mode 100644 index 0000000..bbc6ca6 --- /dev/null +++ b/src/libostree/ostree-types.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include + +#ifndef _OSTREE_PUBLIC +#define _OSTREE_PUBLIC extern +#endif + +G_BEGIN_DECLS + +typedef struct OstreeRepo OstreeRepo; +typedef struct OstreeRepoDevInoCache OstreeRepoDevInoCache; +typedef struct OstreeSePolicy OstreeSePolicy; +typedef struct OstreeSysroot OstreeSysroot; +typedef struct OstreeSysrootUpgrader OstreeSysrootUpgrader; +typedef struct OstreeMutableTree OstreeMutableTree; +typedef struct OstreeRepoFile OstreeRepoFile; +typedef struct OstreeRemote OstreeRemote; + +G_END_DECLS diff --git a/src/libostree/ostree-varint.c b/src/libostree/ostree-varint.c new file mode 100644 index 0000000..0acf21d --- /dev/null +++ b/src/libostree/ostree-varint.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* Significant code derived from protobuf: */ + +/* + * Protocol Buffers - Google's data interchange format + * Copyright 2008 Google Inc. All rights reserved. + * http: *code.google.com/p/protobuf/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "config.h" + +#include "ostree-varint.h" + +static const int max_varint_bytes = 10; + +/** + * _ostree_read_varuint64: + * @buf: (array length=buflen): Byte buffer + * @buflen: Length of bytes in @buf + * @out_value: (out): Value + * @bytes_read: (out): Number of bytes read + * + * Returns: %TRUE on success, %FALSE on end of stream + */ +gboolean +_ostree_read_varuint64 (const guint8 *buf, + gsize buflen, + guint64 *out_value, + gsize *bytes_read) +{ + guint64 result = 0; + int count = 0; + guint8 b; + + /* Adapted from CodedInputStream::ReadVarint64Slow */ + + do + { + if (count == max_varint_bytes) + return FALSE; + if (buflen == 0) + return FALSE; + + b = *buf; + result |= ((guint64)(b & 0x7F)) << (7 * count); + buf++; + buflen--; + ++count; + } while (b & 0x80); + + *bytes_read = count; + *out_value = result; + + return TRUE; +} + +/** + * _ostree_write_varuint64: + * @buf: Target buffer (will contain binary data) + * @n: Integer to encode + * + * Append a varint-encoded version of @n to @buf. + */ +void +_ostree_write_varuint64 (GString *buf, guint64 n) +{ + /* Splitting into 32-bit pieces gives better performance on 32-bit + * processors. */ + guint32 part0 = (guint32)n; + guint32 part1 = (guint32)(n >> 28); + guint32 part2 = (guint32)(n >> 56); + guint8 target[10]; + int i; + int size; + + /* + * Here we can't really optimize for small numbers, since the value is + * split into three parts. Cheking for numbers < 128, for instance, + * would require three comparisons, since you'd have to make sure part1 + * and part2 are zero. However, if the caller is using 64-bit integers, + * it is likely that they expect the numbers to often be very large, so + * we probably don't want to optimize for small numbers anyway. Thus, + * we end up with a hardcoded binary search tree... + */ + if (part2 == 0) { + if (part1 == 0) { + if (part0 < (1 << 14)) { + if (part0 < (1 << 7)) { + size = 1; goto size1; + } else { + size = 2; goto size2; + } + } else { + if (part0 < (1 << 21)) { + size = 3; goto size3; + } else { + size = 4; goto size4; + } + } + } else { + if (part1 < (1 << 14)) { + if (part1 < (1 << 7)) { + size = 5; goto size5; + } else { + size = 6; goto size6; + } + } else { + if (part1 < (1 << 21)) { + size = 7; goto size7; + } else { + size = 8; goto size8; + } + } + } + } else { + if (part2 < (1 << 7)) { + size = 9; goto size9; + } else { + size = 10; goto size10; + } + } + + g_assert_not_reached (); + + size10: target[9] = (guint8)((part2 >> 7) | 0x80); + size9 : target[8] = (guint8)((part2 ) | 0x80); + size8 : target[7] = (guint8)((part1 >> 21) | 0x80); + size7 : target[6] = (guint8)((part1 >> 14) | 0x80); + size6 : target[5] = (guint8)((part1 >> 7) | 0x80); + size5 : target[4] = (guint8)((part1 ) | 0x80); + size4 : target[3] = (guint8)((part0 >> 21) | 0x80); + size3 : target[2] = (guint8)((part0 >> 14) | 0x80); + size2 : target[1] = (guint8)((part0 >> 7) | 0x80); + size1 : target[0] = (guint8)((part0 ) | 0x80); + + target[size-1] &= 0x7F; + + for (i = 0; i < size; i++) + g_string_append_c (buf, target[i]); +} diff --git a/src/libostree/ostree-varint.h b/src/libostree/ostree-varint.h new file mode 100644 index 0000000..eac37f2 --- /dev/null +++ b/src/libostree/ostree-varint.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean _ostree_read_varuint64 (const guint8 *buf, + gsize buflen, + guint64 *out_value, + gsize *bytes_read); + +void _ostree_write_varuint64 (GString *buf, guint64 n); + +G_END_DECLS diff --git a/src/libostree/ostree-version.h b/src/libostree/ostree-version.h new file mode 100644 index 0000000..f9c398e --- /dev/null +++ b/src/libostree/ostree-version.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017 Georges Basile Stavracas Neto + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +/** + * SECTION:ostree-version + * @short_description: ostree version checking + * + * ostree provides macros to check the version of the library + * at compile-time + */ + +/** + * OSTREE_YEAR_VERSION: + * + * ostree year version component (e.g. 2017 if %OSTREE_VERSION is 2017.2) + * + * Since: 2017.4 + */ +#define OSTREE_YEAR_VERSION (2020) + +/** + * OSTREE_RELEASE_VERSION: + * + * ostree release version component (e.g. 2 if %OSTREE_VERSION is 2017.2) + * + * Since: 2017.4 + */ +#define OSTREE_RELEASE_VERSION (4) + +/** + * OSTREE_VERSION + * + * ostree version. + * + * Since: 2017.4 + */ +#define OSTREE_VERSION (2020.4) + +/** + * OSTREE_VERSION_S: + * + * ostree version, encoded as a string, useful for printing and + * concatenation. + * + * Since: 2017.4 + */ +#define OSTREE_VERSION_S "2020.4" + +#define OSTREE_ENCODE_VERSION(year,release) \ + ((year) << 16 | (release)) + +/** + * OSTREE_VERSION_HEX: + * + * ostree version, encoded as an hexadecimal number, useful for + * integer comparisons. + * + * Since: 2017.4 + */ +#define OSTREE_VERSION_HEX \ + (OSTREE_ENCODE_VERSION (OSTREE_YEAR_VERSION, OSTREE_RELEASE_VERSION)) + +/** + * OSTREE_CHECK_VERSION: + * @year: required year version + * @release: required release version + * + * Compile-time version checking. Evaluates to %TRUE if the version + * of ostree is equal or greater than the required one. + * + * Since: 2017.4 + */ +#define OSTREE_CHECK_VERSION(year,release) \ + (OSTREE_YEAR_VERSION > (year) || \ + (OSTREE_YEAR_VERSION == (year) && OSTREE_RELEASE_VERSION >= (release))) + +/** + * OSTREE_BUILT_FEATURES: + * + * Whitespace separated set of features this libostree was configured with at build time. + * Consult the source code in configure.ac (or the CLI `ostree --version`) for examples. + * + * Since: 2019.3 + */ +#define OSTREE_BUILT_FEATURES "libcurl libsoup gpgme ex-fsverity libarchive selinux openssl libmount systemd release p2p" diff --git a/src/libostree/ostree-version.h.in b/src/libostree/ostree-version.h.in new file mode 100644 index 0000000..2c7ecde --- /dev/null +++ b/src/libostree/ostree-version.h.in @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017 Georges Basile Stavracas Neto + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +/** + * SECTION:ostree-version + * @short_description: ostree version checking + * + * ostree provides macros to check the version of the library + * at compile-time + */ + +/** + * OSTREE_YEAR_VERSION: + * + * ostree year version component (e.g. 2017 if %OSTREE_VERSION is 2017.2) + * + * Since: 2017.4 + */ +#define OSTREE_YEAR_VERSION (@YEAR_VERSION@) + +/** + * OSTREE_RELEASE_VERSION: + * + * ostree release version component (e.g. 2 if %OSTREE_VERSION is 2017.2) + * + * Since: 2017.4 + */ +#define OSTREE_RELEASE_VERSION (@RELEASE_VERSION@) + +/** + * OSTREE_VERSION + * + * ostree version. + * + * Since: 2017.4 + */ +#define OSTREE_VERSION (@VERSION@) + +/** + * OSTREE_VERSION_S: + * + * ostree version, encoded as a string, useful for printing and + * concatenation. + * + * Since: 2017.4 + */ +#define OSTREE_VERSION_S "@VERSION@" + +#define OSTREE_ENCODE_VERSION(year,release) \ + ((year) << 16 | (release)) + +/** + * OSTREE_VERSION_HEX: + * + * ostree version, encoded as an hexadecimal number, useful for + * integer comparisons. + * + * Since: 2017.4 + */ +#define OSTREE_VERSION_HEX \ + (OSTREE_ENCODE_VERSION (OSTREE_YEAR_VERSION, OSTREE_RELEASE_VERSION)) + +/** + * OSTREE_CHECK_VERSION: + * @year: required year version + * @release: required release version + * + * Compile-time version checking. Evaluates to %TRUE if the version + * of ostree is equal or greater than the required one. + * + * Since: 2017.4 + */ +#define OSTREE_CHECK_VERSION(year,release) \ + (OSTREE_YEAR_VERSION > (year) || \ + (OSTREE_YEAR_VERSION == (year) && OSTREE_RELEASE_VERSION >= (release))) + +/** + * OSTREE_BUILT_FEATURES: + * + * Whitespace separated set of features this libostree was configured with at build time. + * Consult the source code in configure.ac (or the CLI `ostree --version`) for examples. + * + * Since: 2019.3 + */ +#define OSTREE_BUILT_FEATURES "@OSTREE_FEATURES@" diff --git a/src/libostree/ostree.h b/src/libostree/ostree.h new file mode 100644 index 0000000..0308d0e --- /dev/null +++ b/src/libostree/ostree.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/libotutil/ot-checksum-instream.c b/src/libotutil/ot-checksum-instream.c new file mode 100644 index 0000000..7a704db --- /dev/null +++ b/src/libotutil/ot-checksum-instream.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2017 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-checksum-instream.h" +#include "ot-checksum-utils.h" + +G_DEFINE_TYPE (OtChecksumInstream, ot_checksum_instream, G_TYPE_FILTER_INPUT_STREAM) + +struct _OtChecksumInstreamPrivate { + OtChecksum checksum; +}; + +static gssize ot_checksum_instream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error); + +static void +ot_checksum_instream_finalize (GObject *object) +{ + OtChecksumInstream *self = (OtChecksumInstream*)object; + + ot_checksum_clear (&self->priv->checksum); + + G_OBJECT_CLASS (ot_checksum_instream_parent_class)->finalize (object); +} + +static void +ot_checksum_instream_class_init (OtChecksumInstreamClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (OtChecksumInstreamPrivate)); + + object_class->finalize = ot_checksum_instream_finalize; + stream_class->read_fn = ot_checksum_instream_read; +} + +static void +ot_checksum_instream_init (OtChecksumInstream *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, OT_TYPE_CHECKSUM_INSTREAM, OtChecksumInstreamPrivate); +} + +OtChecksumInstream * +ot_checksum_instream_new (GInputStream *base, + GChecksumType checksum_type) +{ + return ot_checksum_instream_new_with_start (base, checksum_type, NULL, 0); +} + +/* Initialize a checksum stream with starting state from data */ +OtChecksumInstream * +ot_checksum_instream_new_with_start (GInputStream *base, + GChecksumType checksum_type, + const guint8 *buf, + size_t len) +{ + OtChecksumInstream *stream; + + g_return_val_if_fail (G_IS_INPUT_STREAM (base), NULL); + + stream = g_object_new (OT_TYPE_CHECKSUM_INSTREAM, + "base-stream", base, + NULL); + + /* For now */ + g_assert (checksum_type == G_CHECKSUM_SHA256); + ot_checksum_init (&stream->priv->checksum); + if (buf) + ot_checksum_update (&stream->priv->checksum, buf, len); + + return (OtChecksumInstream*) (stream); +} + +static gssize +ot_checksum_instream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + OtChecksumInstream *self = (OtChecksumInstream*) stream; + GFilterInputStream *fself = (GFilterInputStream*) self; + gssize res = -1; + + res = g_input_stream_read (fself->base_stream, + buffer, + count, + cancellable, + error); + if (res > 0) + ot_checksum_update (&self->priv->checksum, buffer, res); + + return res; +} + +char * +ot_checksum_instream_get_string (OtChecksumInstream *stream) +{ + char buf[_OSTREE_SHA256_STRING_LEN+1]; + ot_checksum_get_hexdigest (&stream->priv->checksum, buf, sizeof(buf)); + return g_strndup (buf, sizeof(buf)); +} diff --git a/src/libotutil/ot-checksum-instream.h b/src/libotutil/ot-checksum-instream.h new file mode 100644 index 0000000..3dcdff9 --- /dev/null +++ b/src/libotutil/ot-checksum-instream.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define OT_TYPE_CHECKSUM_INSTREAM (ot_checksum_instream_get_type ()) +#define OT_CHECKSUM_INSTREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OT_TYPE_CHECKSUM_INPUT_STREAM, OtChecksumInstream)) +#define OT_CHECKSUM_INSTREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OT_TYPE_CHECKSUM_INPUT_STREAM, OtChecksumInstreamClass)) +#define OT_IS_CHECKSUM_INSTREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OT_TYPE_CHECKSUM_INPUT_STREAM)) +#define OT_IS_CHECKSUM_INSTREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OT_TYPE_CHECKSUM_INPUT_STREAM)) +#define OT_CHECKSUM_INSTREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OT_TYPE_CHECKSUM_INPUT_STREAM, OtChecksumInstreamClass)) + +typedef struct _OtChecksumInstream OtChecksumInstream; +typedef struct _OtChecksumInstreamClass OtChecksumInstreamClass; +typedef struct _OtChecksumInstreamPrivate OtChecksumInstreamPrivate; + +struct _OtChecksumInstream +{ + GFilterInputStream parent_instance; + + /*< private >*/ + OtChecksumInstreamPrivate *priv; +}; + +struct _OtChecksumInstreamClass +{ + GFilterInputStreamClass parent_class; +}; + +GType ot_checksum_instream_get_type (void) G_GNUC_CONST; + +OtChecksumInstream * ot_checksum_instream_new (GInputStream *stream, GChecksumType checksum); +OtChecksumInstream * ot_checksum_instream_new_with_start (GInputStream *stream, GChecksumType checksum, + const guint8 *buf, size_t len); + +char * ot_checksum_instream_get_string (OtChecksumInstream *stream); + +G_END_DECLS diff --git a/src/libotutil/ot-checksum-utils.c b/src/libotutil/ot-checksum-utils.c new file mode 100644 index 0000000..6676736 --- /dev/null +++ b/src/libotutil/ot-checksum-utils.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "otutil.h" +#if defined(HAVE_OPENSSL) +#include +#elif defined(HAVE_GNUTLS) +#include +#include +#endif + +#include + +void +ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len) +{ + static const gchar hexchars[] = "0123456789abcdef"; + guint i, j; + + for (i = 0, j = 0; i < len; i++, j += 2) + { + guchar byte = inbuf[i]; + out_buf[j] = hexchars[byte >> 4]; + out_buf[j+1] = hexchars[byte & 0xF]; + } + out_buf[j] = '\0'; +} + +/* I like to think of this as AbstractChecksumProxyFactoryBean. In homage to + * https://news.ycombinator.com/item?id=4549544 + * aka http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.html + */ +typedef struct { + gboolean initialized; + gboolean closed; +#if defined(HAVE_OPENSSL) + EVP_MD_CTX *checksum; +#elif defined(HAVE_GNUTLS) + gnutls_hash_hd_t checksum; +#else + GChecksum *checksum; +#endif + guint digest_len; +} OtRealChecksum; + +G_STATIC_ASSERT (sizeof (OtChecksum) >= sizeof (OtRealChecksum)); + +void +ot_checksum_init (OtChecksum *checksum) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + g_return_if_fail (!real->initialized); +#if defined(HAVE_OPENSSL) + real->checksum = EVP_MD_CTX_create (); + g_assert (real->checksum); + g_assert (EVP_DigestInit_ex (real->checksum, EVP_sha256 (), NULL)); + real->digest_len = EVP_MD_CTX_size (real->checksum); +#elif defined(HAVE_GNUTLS) + g_assert (!gnutls_hash_init (&real->checksum, GNUTLS_DIG_SHA256)); + real->digest_len = gnutls_hash_get_len (GNUTLS_DIG_SHA256); +#else + real->checksum = g_checksum_new (G_CHECKSUM_SHA256); + real->digest_len = g_checksum_type_get_length (G_CHECKSUM_SHA256); +#endif + g_assert_cmpint (real->digest_len, ==, _OSTREE_SHA256_DIGEST_LEN); + real->closed = FALSE; + real->initialized = TRUE; +} + +void +ot_checksum_update (OtChecksum *checksum, + const guint8 *buf, + size_t len) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + g_return_if_fail (real->initialized); + g_return_if_fail (!real->closed); +#if defined(HAVE_OPENSSL) + g_assert (EVP_DigestUpdate (real->checksum, buf, len)); +#elif defined(HAVE_GNUTLS) + g_assert (!gnutls_hash (real->checksum, buf, len)); +#else + g_checksum_update (real->checksum, buf, len); +#endif +} + +static void +ot_checksum_get_digest_internal (OtRealChecksum *real, + guint8 *buf, + size_t buflen) +{ + g_return_if_fail (real->initialized); + g_assert_cmpint (buflen, ==, _OSTREE_SHA256_DIGEST_LEN); +#if defined(HAVE_OPENSSL) + guint digest_len = buflen; + g_assert (EVP_DigestFinal_ex (real->checksum, buf, &digest_len)); + g_assert_cmpint (digest_len, ==, buflen); +#elif defined(HAVE_GNUTLS) + gnutls_hash_output (real->checksum, buf); +#else + gsize digest_len = buflen; + g_checksum_get_digest (real->checksum, buf, &digest_len); + g_assert_cmpint (digest_len, ==, buflen); +#endif +} + +void +ot_checksum_get_digest (OtChecksum *checksum, + guint8 *buf, + size_t buflen) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + ot_checksum_get_digest_internal (real, buf, buflen); + real->closed = TRUE; +} + +void +ot_checksum_get_hexdigest (OtChecksum *checksum, + char *buf, + size_t buflen) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + const guint digest_len = real->digest_len; + guint8 digest_buf[digest_len]; + ot_checksum_get_digest (checksum, digest_buf, digest_len); + ot_bin2hex (buf, (guint8*)digest_buf, digest_len); +} + +void +ot_checksum_clear (OtChecksum *checksum) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + if (!real->initialized) + return; +#if defined(HAVE_OPENSSL) + EVP_MD_CTX_destroy (real->checksum); +#elif defined(HAVE_GNUTLS) + gnutls_hash_deinit (real->checksum, NULL); +#else + g_checksum_free (real->checksum); +#endif + real->initialized = FALSE; +} + +guchar * +ot_csum_from_gchecksum (GChecksum *checksum) +{ + guchar *ret = g_malloc (32); + gsize len = 32; + + g_checksum_get_digest (checksum, ret, &len); + g_assert (len == 32); + return ret; +} + +gboolean +ot_gio_write_update_checksum (GOutputStream *out, + gconstpointer data, + gsize len, + gsize *out_bytes_written, + OtChecksum *checksum, + GCancellable *cancellable, + GError **error) +{ + if (out) + { + if (!g_output_stream_write_all (out, data, len, out_bytes_written, + cancellable, error)) + return FALSE; + } + else if (out_bytes_written) + { + *out_bytes_written = len; + } + + if (checksum) + ot_checksum_update (checksum, data, len); + return TRUE; +} + +gboolean +ot_gio_splice_update_checksum (GOutputStream *out, + GInputStream *in, + OtChecksum *checksum, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (out != NULL || checksum != NULL, FALSE); + + if (checksum != NULL) + { + gsize bytes_read, bytes_written; + char buf[4096]; + do + { + if (!g_input_stream_read_all (in, buf, sizeof (buf), &bytes_read, cancellable, error)) + return FALSE; + if (!ot_gio_write_update_checksum (out, buf, bytes_read, &bytes_written, checksum, + cancellable, error)) + return FALSE; + } + while (bytes_read > 0); + } + else if (out != NULL) + { + if (g_output_stream_splice (out, in, 0, cancellable, error) < 0) + return FALSE; + } + + return TRUE; +} + +/* Copy @in to @out, return in @out_csum the binary checksum for + * all data read. + */ +gboolean +ot_gio_splice_get_checksum (GOutputStream *out, + GInputStream *in, + guchar **out_csum, + GCancellable *cancellable, + GError **error) +{ + g_auto(OtChecksum) checksum = { 0, }; + ot_checksum_init (&checksum); + + if (!ot_gio_splice_update_checksum (out, in, &checksum, cancellable, error)) + return FALSE; + + guint8 digest[_OSTREE_SHA256_DIGEST_LEN]; + ot_checksum_get_digest (&checksum, digest, sizeof (digest)); + if (out_csum) + *out_csum = g_memdup (digest, sizeof (digest)); + return TRUE; +} + +char * +ot_checksum_file_at (int dfd, + const char *path, + GChecksumType checksum_type, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GInputStream) in = NULL; + if (!ot_openat_read_stream (dfd, path, TRUE, &in, cancellable, error)) + return FALSE; + + g_auto(OtChecksum) checksum = { 0, }; + ot_checksum_init (&checksum); + if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error)) + return FALSE; + + char hexdigest[_OSTREE_SHA256_STRING_LEN+1]; + ot_checksum_get_hexdigest (&checksum, hexdigest, sizeof (hexdigest)); + return g_strdup (hexdigest); +} diff --git a/src/libotutil/ot-checksum-utils.h b/src/libotutil/ot-checksum-utils.h new file mode 100644 index 0000000..411ef25 --- /dev/null +++ b/src/libotutil/ot-checksum-utils.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2011 Colin Walters . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include "libglnx.h" + +G_BEGIN_DECLS + +void ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len); + +guchar *ot_csum_from_gchecksum (GChecksum *checksum); + +struct OtChecksum { + gboolean initialized; + guint uints[2]; + gpointer data[2]; +}; +typedef struct OtChecksum OtChecksum; + +/* Same as OSTREE_SHA256_DIGEST_LEN, but this header can't depend on that */ +#define _OSTREE_SHA256_DIGEST_LEN (32) +#if defined(OSTREE_SHA256_DIGEST_LEN) && _OSTREE_SHA256_DIGEST_LEN != OSTREE_SHA256_DIGEST_LEN +#error Mismatched OSTREE_SHA256_DIGEST_LEN +#endif +/* See above */ +#define _OSTREE_SHA256_STRING_LEN (64) +#if defined(OSTREE_SHA256_STRING_LEN) && _OSTREE_SHA256_STRING_LEN != OSTREE_SHA256_STRING_LEN +#error Mismatched OSTREE_SHA256_STRING_LEN +#endif + +void ot_checksum_init (OtChecksum *checksum); +void ot_checksum_update (OtChecksum *checksum, + const guint8 *buf, + size_t len); +static inline void +ot_checksum_update_bytes (OtChecksum *checksum, + GBytes *buf) +{ + gsize len; + const guint8 *bufdata = g_bytes_get_data (buf, &len); + ot_checksum_update (checksum, bufdata, len); +} +void ot_checksum_get_digest (OtChecksum *checksum, + guint8 *buf, + size_t buflen); +void ot_checksum_get_hexdigest (OtChecksum *checksum, + char *buf, + size_t buflen); +void ot_checksum_clear (OtChecksum *checksum); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OtChecksum, ot_checksum_clear) + +gboolean ot_gio_write_update_checksum (GOutputStream *out, + gconstpointer data, + gsize len, + gsize *out_bytes_written, + OtChecksum *checksum, + GCancellable *cancellable, + GError **error); + +gboolean ot_gio_splice_get_checksum (GOutputStream *out, + GInputStream *in, + guchar **out_csum, + GCancellable *cancellable, + GError **error); + +gboolean ot_gio_splice_update_checksum (GOutputStream *out, + GInputStream *in, + OtChecksum *checksum, + GCancellable *cancellable, + GError **error); + +char * ot_checksum_file_at (int dfd, + const char *path, + GChecksumType checksum_type, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/src/libotutil/ot-fs-utils.c b/src/libotutil/ot-fs-utils.c new file mode 100644 index 0000000..c4fcd56 --- /dev/null +++ b/src/libotutil/ot-fs-utils.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-fs-utils.h" +#include "libglnx.h" +#include +#include +#include +#include + +/* Convert a fd-relative path to a GFile* - use + * for legacy code. + */ +GFile * +ot_fdrel_to_gfile (int dfd, const char *path) +{ + g_autofree char *abspath = glnx_fdrel_abspath (dfd, path); + return g_file_new_for_path (abspath); +} + +/* Wraps readlinkat(), and sets the `symlink-target` property + * of @target_info. + */ +gboolean +ot_readlinkat_gfile_info (int dfd, + const char *path, + GFileInfo *target_info, + GCancellable *cancellable, + GError **error) +{ + char targetbuf[PATH_MAX+1]; + ssize_t len; + + if (TEMP_FAILURE_RETRY (len = readlinkat (dfd, path, targetbuf, sizeof (targetbuf) - 1)) < 0) + return glnx_throw_errno_prefix (error, "readlinkat"); + targetbuf[len] = '\0'; + g_file_info_set_symlink_target (target_info, targetbuf); + + return TRUE; +} + +/** + * ot_openat_read_stream: + * @dfd: Directory file descriptor + * @path: Subpath + * @follow: Whether or not to follow symbolic links + * @out_istream: (out): Return location for input stream + * @cancellable: Cancellable + * @error: Error + * + * Open a file for reading starting from @dfd for @path. + * The @follow parameter determines whether or not to follow + * if the last element of @path is a symbolic link. Intermediate + * symlink path components are always followed. + */ +gboolean +ot_openat_read_stream (int dfd, + const char *path, + gboolean follow, + GInputStream **out_istream, + GCancellable *cancellable, + GError **error) +{ + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (dfd, path, follow, &fd, error)) + return FALSE; + *out_istream = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE); + return TRUE; +} + +/* Like unlinkat() but ignore ENOENT */ +gboolean +ot_ensure_unlinked_at (int dfd, + const char *path, + GError **error) +{ + if (unlinkat (dfd, path, 0) != 0) + { + if (G_UNLIKELY (errno != ENOENT)) + return glnx_throw_errno_prefix (error, "unlink(%s)", path); + } + return TRUE; +} + +gboolean +ot_openat_ignore_enoent (int dfd, + const char *path, + int *out_fd, + GError **error) +{ + int target_fd = openat (dfd, path, O_CLOEXEC | O_RDONLY); + if (target_fd < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "openat(%s)", path); + } + + *out_fd = target_fd; + return TRUE; +} + +/* Like glnx_dirfd_iterator_init_at(), but if %ENOENT, then set + * @out_exists to %FALSE, and return successfully. + */ +gboolean +ot_dfd_iter_init_allow_noent (int dfd, + const char *path, + GLnxDirFdIterator *dfd_iter, + gboolean *out_exists, + GError **error) +{ + glnx_autofd int fd = glnx_opendirat_with_errno (dfd, path, TRUE); + if (fd < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "opendirat"); + *out_exists = FALSE; + return TRUE; + } + if (!glnx_dirfd_iterator_init_take_fd (&fd, dfd_iter, error)) + return FALSE; + *out_exists = TRUE; + return TRUE; +} + +typedef struct { + gpointer addr; + gsize len; +} MapData; + +static void +map_data_destroy (gpointer data) +{ + MapData *mdata = data; + (void) munmap (mdata->addr, mdata->len); + g_free (mdata); +} + +/* Return a newly-allocated GBytes that refers to the contents of the file + * starting at offset @start. If the file is large enough, mmap() may be used. + */ +GBytes * +ot_fd_readall_or_mmap (int fd, + goffset start, + GError **error) +{ + struct stat stbuf; + if (!glnx_fstat (fd, &stbuf, error)) + return FALSE; + + /* http://stackoverflow.com/questions/258091/when-should-i-use-mmap-for-file-access */ + if (start > stbuf.st_size) + return g_bytes_new_static (NULL, 0); + const gsize len = stbuf.st_size - start; + if (len > 16*1024) + { + /* The reason we don't use g_mapped_file_new_from_fd() here + * is it doesn't support passing an offset, which is actually + * used by the static delta code. + */ + gpointer map = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, start); + if (map == (void*)-1) + return glnx_null_throw_errno_prefix (error, "mmap"); + + MapData *mdata = g_new (MapData, 1); + mdata->addr = map; + mdata->len = len; + + return g_bytes_new_with_free_func (map, len, map_data_destroy, mdata); + } + + /* Fall through to plain read into a malloc buffer */ + if (lseek (fd, start, SEEK_SET) < 0) + return glnx_null_throw_errno_prefix (error, "lseek"); + /* Not cancellable since this should be small */ + return glnx_fd_readall_bytes (fd, NULL, error); +} + +/* Given an input stream, splice it to an anonymous file (O_TMPFILE). + * Useful for potentially large but transient files. + */ +GBytes * +ot_map_anonymous_tmpfile_from_content (GInputStream *instream, + GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_anonymous_tmpfile (O_RDWR | O_CLOEXEC, &tmpf, error)) + return NULL; + + g_autoptr(GOutputStream) out = g_unix_output_stream_new (tmpf.fd, FALSE); + gssize n_bytes_written = g_output_stream_splice (out, instream, + G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, + cancellable, error); + if (n_bytes_written < 0) + return NULL; + + g_autoptr(GMappedFile) mfile = g_mapped_file_new_from_fd (tmpf.fd, FALSE, error); + if (!mfile) + return NULL; + return g_mapped_file_get_bytes (mfile); +} + +gboolean +ot_parse_file_by_line (const char *path, + gboolean (*cb)(const char*, void*, GError**), + void *cbdata, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *contents = + glnx_file_get_contents_utf8_at (AT_FDCWD, path, NULL, cancellable, error); + if (!contents) + return FALSE; + + g_auto(GStrv) lines = g_strsplit (contents, "\n", -1); + for (char **iter = lines; iter && *iter; iter++) + { + /* skip empty lines at least */ + if (**iter == '\0') + continue; + + if (!cb (*iter, cbdata, error)) + return FALSE; + } + + return TRUE; +} diff --git a/src/libotutil/ot-fs-utils.h b/src/libotutil/ot-fs-utils.h new file mode 100644 index 0000000..74a0fed --- /dev/null +++ b/src/libotutil/ot-fs-utils.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 Colin Walters . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "ot-unix-utils.h" +#include "libglnx.h" + +G_BEGIN_DECLS + +/* A little helper to call unlinkat() as a cleanup + * function. Mostly only necessary to handle + * deletion of temporary symlinks. + */ +typedef struct { + int dfd; + char *path; +} OtCleanupUnlinkat; + +static inline void +ot_cleanup_unlinkat_clear (OtCleanupUnlinkat *cleanup) +{ + g_clear_pointer (&cleanup->path, g_free); +} + +static inline void +ot_cleanup_unlinkat (OtCleanupUnlinkat *cleanup) +{ + if (cleanup->path) + { + (void) unlinkat (cleanup->dfd, cleanup->path, 0); + ot_cleanup_unlinkat_clear (cleanup); + } +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OtCleanupUnlinkat, ot_cleanup_unlinkat) + +GFile * ot_fdrel_to_gfile (int dfd, const char *path); + +gboolean ot_readlinkat_gfile_info (int dfd, + const char *path, + GFileInfo *target_info, + GCancellable *cancellable, + GError **error); + +gboolean ot_openat_read_stream (int dfd, + const char *path, + gboolean follow, + GInputStream **out_istream, + GCancellable *cancellable, + GError **error); + +gboolean ot_ensure_unlinked_at (int dfd, + const char *path, + GError **error); + +gboolean ot_openat_ignore_enoent (int dfd, + const char *path, + int *out_fd, + GError **error); + +gboolean ot_dfd_iter_init_allow_noent (int dfd, + const char *path, + GLnxDirFdIterator *dfd_iter, + gboolean *out_exists, + GError **error); + +GBytes * +ot_map_anonymous_tmpfile_from_content (GInputStream *instream, + GCancellable *cancellable, + GError **error); + +GBytes *ot_fd_readall_or_mmap (int fd, goffset offset, + GError **error); + +gboolean +ot_parse_file_by_line (const char *path, + gboolean (*cb)(const char*, void*, GError**), + void *cbdata, + GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/src/libotutil/ot-gio-utils.c b/src/libotutil/ot-gio-utils.c new file mode 100644 index 0000000..f09ee8a --- /dev/null +++ b/src/libotutil/ot-gio-utils.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include "otutil.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +GFile * +ot_gfile_resolve_path_printf (GFile *path, + const char *format, + ...) +{ + va_list args; + g_autofree char *relpath = NULL; + + va_start (args, format); + relpath = g_strdup_vprintf (format, args); + va_end (args); + + return g_file_resolve_relative_path (path, relpath); +} + +/** + * ot_gfile_replace_contents_fsync: + * + * Like g_file_replace_contents(), except always uses fdatasync(). + */ +gboolean +ot_gfile_replace_contents_fsync (GFile *path, + GBytes *contents, + GCancellable *cancellable, + GError **error) +{ + gsize len; + const guint8*buf = g_bytes_get_data (contents, &len); + + return glnx_file_replace_contents_at (AT_FDCWD, gs_file_get_path_cached (path), + buf, len, + GLNX_FILE_REPLACE_DATASYNC_NEW, + cancellable, error); +} + +/** + * ot_gfile_ensure_unlinked: + * + * Like gs_file_unlink(), but return successfully if the file doesn't + * exist. + */ +gboolean +ot_gfile_ensure_unlinked (GFile *path, + GCancellable *cancellable, + GError **error) +{ + if (unlink (gs_file_get_path_cached (path)) != 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "unlink(%s)", gs_file_get_path_cached (path)); + } + return TRUE; +} + +#if !GLIB_CHECK_VERSION(2, 44, 0) + +gboolean +ot_file_enumerator_iterate (GFileEnumerator *direnum, + GFileInfo **out_info, + GFile **out_child, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GError *temp_error = NULL; + + static GQuark cached_info_quark; + static GQuark cached_child_quark; + static gsize quarks_initialized; + + g_return_val_if_fail (direnum != NULL, FALSE); + g_return_val_if_fail (out_info != NULL, FALSE); + + if (g_once_init_enter (&quarks_initialized)) + { + cached_info_quark = g_quark_from_static_string ("ot-cached-info"); + cached_child_quark = g_quark_from_static_string ("ot-cached-child"); + g_once_init_leave (&quarks_initialized, 1); + } + + *out_info = g_file_enumerator_next_file (direnum, cancellable, &temp_error); + if (out_child) + *out_child = NULL; + if (temp_error != NULL) + { + g_propagate_error (error, temp_error); + goto out; + } + else if (*out_info != NULL) + { + g_object_set_qdata_full ((GObject*)direnum, cached_info_quark, *out_info, (GDestroyNotify)g_object_unref); + if (out_child != NULL) + { + const char *name = g_file_info_get_name (*out_info); + *out_child = g_file_get_child (g_file_enumerator_get_container (direnum), name); + g_object_set_qdata_full ((GObject*)direnum, cached_child_quark, *out_child, (GDestroyNotify)g_object_unref); + } + } + + ret = TRUE; + out: + return ret; +} + +#endif + +G_LOCK_DEFINE_STATIC (pathname_cache); + +/** + * ot_file_get_path_cached: + * + * Like g_file_get_path(), but returns a constant copy so callers + * don't need to free the result. + */ +const char * +ot_file_get_path_cached (GFile *file) +{ + const char *path; + static GQuark _file_path_quark = 0; + + if (G_UNLIKELY (_file_path_quark) == 0) + _file_path_quark = g_quark_from_static_string ("gsystem-file-path"); + + G_LOCK (pathname_cache); + + path = g_object_get_qdata ((GObject*)file, _file_path_quark); + if (!path) + { + path = g_file_get_path (file); + if (path == NULL) + { + G_UNLOCK (pathname_cache); + return NULL; + } + g_object_set_qdata_full ((GObject*)file, _file_path_quark, (char*)path, (GDestroyNotify)g_free); + } + + G_UNLOCK (pathname_cache); + + return path; +} diff --git a/src/libotutil/ot-gio-utils.h b/src/libotutil/ot-gio-utils.h new file mode 100644 index 0000000..d317ac2 --- /dev/null +++ b/src/libotutil/ot-gio-utils.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 Colin Walters . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +/* Basically the stuff that comes from stat() and cheap calls like + * readlink(). Other things require opening the file, or also + * stat()ing the parent directory. + */ +#define OSTREE_GIO_FAST_QUERYINFO ("standard::name,standard::type,standard::size,standard::is-symlink,standard::symlink-target," \ + "unix::device,unix::inode,unix::mode,unix::uid,unix::gid,unix::rdev") + +GFile * ot_gfile_resolve_path_printf (GFile *path, + const char *format, + ...) G_GNUC_PRINTF(2, 3); + +gboolean ot_gfile_replace_contents_fsync (GFile *path, + GBytes *contents, + GCancellable *cancellable, + GError **error); + +gboolean ot_gfile_ensure_unlinked (GFile *path, + GCancellable *cancellable, + GError **error); + +#if !GLIB_CHECK_VERSION(2, 44, 0) +gboolean +ot_file_enumerator_iterate (GFileEnumerator *direnum, + GFileInfo **out_info, + GFile **out_child, + GCancellable *cancellable, + GError **error); +#else +static inline gboolean +ot_file_enumerator_iterate (GFileEnumerator *direnum, + GFileInfo **out_info, + GFile **out_child, + GCancellable *cancellable, + GError **error) +{ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + return (g_file_enumerator_iterate) (direnum, out_info, out_child, cancellable, error); + G_GNUC_END_IGNORE_DEPRECATIONS; +} +#endif +#define g_file_enumerator_iterate ot_file_enumerator_iterate + +const char * +ot_file_get_path_cached (GFile *file); + +static inline +const char * +gs_file_get_path_cached (GFile *file) +{ + return ot_file_get_path_cached (file); +} + +G_END_DECLS diff --git a/src/libotutil/ot-gpg-utils.c b/src/libotutil/ot-gpg-utils.c new file mode 100644 index 0000000..743d941 --- /dev/null +++ b/src/libotutil/ot-gpg-utils.c @@ -0,0 +1,540 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-gpg-utils.h" + +#include + +#include +#include "libglnx.h" + +/* Like glnx_throw_errno_prefix, but takes @gpg_error */ +gboolean +ot_gpgme_throw (gpgme_error_t gpg_error, GError **error, + const char *fmt, ...) +{ + if (error == NULL) + return FALSE; + + GIOErrorEnum errcode; + char errbuf[1024]; + + /* XXX This list is incomplete. Add cases as needed. */ + switch (gpgme_err_code (gpg_error)) + { + /* special case - shouldn't be here */ + case GPG_ERR_NO_ERROR: + g_assert_not_reached (); + + /* special case - abort on out-of-memory */ + case GPG_ERR_ENOMEM: + (void) gpg_strerror_r (gpg_error, errbuf, sizeof (errbuf)); + errbuf[sizeof(errbuf)-1] = '\0'; + g_error ("%s: %s", + gpgme_strsource (gpg_error), + errbuf); + + case GPG_ERR_INV_VALUE: + errcode = G_IO_ERROR_INVALID_ARGUMENT; + break; + + default: + errcode = G_IO_ERROR_FAILED; + break; + } + + (void) gpg_strerror_r (gpg_error, errbuf, sizeof (errbuf)); + errbuf[sizeof(errbuf)-1] = '\0'; + g_set_error (error, G_IO_ERROR, errcode, "%s: %s", + gpgme_strsource (gpg_error), + errbuf); + va_list args; + va_start (args, fmt); + glnx_real_set_prefix_error_va (*error, fmt, args); + va_end (args); + + return FALSE; +} + +gboolean +ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, + char **out_tmp_home_dir, + GOutputStream **out_pubring_stream, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *tmp_home_dir = NULL; + gpgme_error_t gpg_error; + gboolean ret = FALSE; + + g_return_val_if_fail (gpgme_ctx != NULL, FALSE); + + /* GPGME has no API for using multiple keyrings (aka, gpg --keyring), + * so we create a temporary directory and tell GPGME to use it as the + * home directory. Then (optionally) create a pubring.gpg file there + * and hand the caller an open output stream to concatenate necessary + * keyring files. */ + + tmp_home_dir = g_build_filename (g_get_tmp_dir (), "ostree-gpg-XXXXXX", NULL); + + if (mkdtemp (tmp_home_dir) == NULL) + { + glnx_set_error_from_errno (error); + goto out; + } + + /* Not documented, but gpgme_ctx_set_engine_info() accepts NULL for + * the executable file name, which leaves the old setting unchanged. */ + gpg_error = gpgme_ctx_set_engine_info (gpgme_ctx, + GPGME_PROTOCOL_OpenPGP, + NULL, tmp_home_dir); + if (gpg_error != GPG_ERR_NO_ERROR) + { + ot_gpgme_throw (gpg_error, error, "gpgme_ctx_set_engine_info"); + goto out; + } + + if (out_pubring_stream != NULL) + { + GFileOutputStream *pubring_stream; + g_autoptr(GFile) pubring_file = NULL; + g_autofree char *pubring_path = NULL; + + pubring_path = g_build_filename (tmp_home_dir, "pubring.gpg", NULL); + pubring_file = g_file_new_for_path (pubring_path); + + pubring_stream = g_file_create (pubring_file, + G_FILE_CREATE_NONE, + cancellable, error); + if (pubring_stream == NULL) + goto out; + + /* Sneaky cast from GFileOutputStream to GOutputStream. */ + *out_pubring_stream = g_steal_pointer (&pubring_stream); + } + + if (out_tmp_home_dir != NULL) + *out_tmp_home_dir = g_steal_pointer (&tmp_home_dir); + + ret = TRUE; + +out: + if (!ret) + { + /* Clean up our mess on error. */ + (void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_home_dir, NULL, NULL); + } + + return ret; +} + +/**** The functions below are based on seahorse-gpgme-data.c ****/ + +static void +set_errno_from_gio_error (GError *error) +{ + /* This is the reverse of g_io_error_from_errno() */ + + g_return_if_fail (error != NULL); + + switch (error->code) + { + case G_IO_ERROR_FAILED: + errno = EIO; + break; + case G_IO_ERROR_NOT_FOUND: + errno = ENOENT; + break; + case G_IO_ERROR_EXISTS: + errno = EEXIST; + break; + case G_IO_ERROR_IS_DIRECTORY: + errno = EISDIR; + break; + case G_IO_ERROR_NOT_DIRECTORY: + errno = ENOTDIR; + break; + case G_IO_ERROR_NOT_EMPTY: + errno = ENOTEMPTY; + break; + case G_IO_ERROR_NOT_REGULAR_FILE: + case G_IO_ERROR_NOT_SYMBOLIC_LINK: + case G_IO_ERROR_NOT_MOUNTABLE_FILE: + errno = EBADF; + break; + case G_IO_ERROR_FILENAME_TOO_LONG: + errno = ENAMETOOLONG; + break; + case G_IO_ERROR_INVALID_FILENAME: + errno = EINVAL; + break; + case G_IO_ERROR_TOO_MANY_LINKS: + errno = EMLINK; + break; + case G_IO_ERROR_NO_SPACE: + errno = ENOSPC; + break; + case G_IO_ERROR_INVALID_ARGUMENT: + errno = EINVAL; + break; + case G_IO_ERROR_PERMISSION_DENIED: + errno = EPERM; + break; + case G_IO_ERROR_NOT_SUPPORTED: + errno = ENOTSUP; + break; + case G_IO_ERROR_NOT_MOUNTED: + errno = ENOENT; + break; + case G_IO_ERROR_ALREADY_MOUNTED: + errno = EALREADY; + break; + case G_IO_ERROR_CLOSED: + errno = EBADF; + break; + case G_IO_ERROR_CANCELLED: + errno = EINTR; + break; + case G_IO_ERROR_PENDING: + errno = EALREADY; + break; + case G_IO_ERROR_READ_ONLY: + errno = EACCES; + break; + case G_IO_ERROR_CANT_CREATE_BACKUP: + errno = EIO; + break; + case G_IO_ERROR_WRONG_ETAG: + errno = EACCES; + break; + case G_IO_ERROR_TIMED_OUT: + errno = EIO; + break; + case G_IO_ERROR_WOULD_RECURSE: + errno = ELOOP; + break; + case G_IO_ERROR_BUSY: + errno = EBUSY; + break; + case G_IO_ERROR_WOULD_BLOCK: + errno = EWOULDBLOCK; + break; + case G_IO_ERROR_HOST_NOT_FOUND: + errno = EHOSTDOWN; + break; + case G_IO_ERROR_WOULD_MERGE: + errno = EIO; + break; + case G_IO_ERROR_FAILED_HANDLED: + errno = 0; + break; + default: + errno = EIO; + break; + } +} + +static ssize_t +data_read_cb (void *handle, void *buffer, size_t size) +{ + GInputStream *input_stream = handle; + gsize bytes_read; + GError *local_error = NULL; + + g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), -1); + + if (!g_input_stream_read_all (input_stream, buffer, size, + &bytes_read, NULL, &local_error)) + { + set_errno_from_gio_error (local_error); + g_clear_error (&local_error); + bytes_read = -1; + } + + return bytes_read; +} + +static ssize_t +data_write_cb (void *handle, const void *buffer, size_t size) +{ + GOutputStream *output_stream = handle; + gsize bytes_written; + GError *local_error = NULL; + + g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), -1); + + if (g_output_stream_write_all (output_stream, buffer, size, + &bytes_written, NULL, &local_error)) + { + (void)g_output_stream_flush (output_stream, NULL, &local_error); + } + + if (local_error != NULL) + { + set_errno_from_gio_error (local_error); + g_clear_error (&local_error); + bytes_written = -1; + } + + return bytes_written; +} + +static off_t +data_seek_cb (void *handle, off_t offset, int whence) +{ + GObject *stream = handle; + GSeekable *seekable; + GSeekType seek_type = 0; + off_t position = -1; + GError *local_error = NULL; + + g_return_val_if_fail (G_IS_INPUT_STREAM (stream) || + G_IS_OUTPUT_STREAM (stream), -1); + + if (!G_IS_SEEKABLE (stream)) { + errno = EOPNOTSUPP; + goto out; + } + + switch (whence) + { + case SEEK_SET: + seek_type = G_SEEK_SET; + break; + case SEEK_CUR: + seek_type = G_SEEK_CUR; + break; + case SEEK_END: + seek_type = G_SEEK_END; + break; + default: + g_assert_not_reached (); + } + + seekable = G_SEEKABLE (stream); + + if (!g_seekable_seek (seekable, offset, seek_type, NULL, &local_error)) + { + set_errno_from_gio_error (local_error); + g_clear_error (&local_error); + goto out; + } + + position = g_seekable_tell (seekable); + +out: + return position; +} + +static void +data_release_cb (void *handle) +{ + GObject *stream = handle; + + g_return_if_fail (G_IS_INPUT_STREAM (stream) || + G_IS_OUTPUT_STREAM (stream)); + + g_object_unref (stream); +} + +static struct gpgme_data_cbs data_input_cbs = { + data_read_cb, + NULL, + data_seek_cb, + data_release_cb +}; + +static struct gpgme_data_cbs data_output_cbs = { + NULL, + data_write_cb, + data_seek_cb, + data_release_cb +}; + +gpgme_data_t +ot_gpgme_data_input (GInputStream *input_stream) +{ + gpgme_data_t data = NULL; + gpgme_error_t gpg_error; + + g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), NULL); + + gpg_error = gpgme_data_new_from_cbs (&data, &data_input_cbs, input_stream); + + /* The only possible error is ENOMEM, which we abort on. */ + if (gpg_error != GPG_ERR_NO_ERROR) + { + g_assert (gpgme_err_code (gpg_error) == GPG_ERR_ENOMEM); + g_assert_not_reached (); + } + + g_object_ref (input_stream); + + return data; +} + +gpgme_data_t +ot_gpgme_data_output (GOutputStream *output_stream) +{ + gpgme_data_t data = NULL; + gpgme_error_t gpg_error; + + g_return_val_if_fail (G_IS_OUTPUT_STREAM (output_stream), NULL); + + gpg_error = gpgme_data_new_from_cbs (&data, &data_output_cbs, output_stream); + + /* The only possible error is ENOMEM, which we abort on. */ + if (gpg_error != GPG_ERR_NO_ERROR) + { + g_assert (gpgme_err_code (gpg_error) == GPG_ERR_ENOMEM); + g_assert_not_reached (); + } + + g_object_ref (output_stream); + + return data; +} + +gpgme_ctx_t +ot_gpgme_new_ctx (const char *homedir, + GError **error) +{ + gpgme_error_t err; + g_auto(gpgme_ctx_t) context = NULL; + + if ((err = gpgme_new (&context)) != GPG_ERR_NO_ERROR) + return ot_gpgme_throw (err, error, "Unable to create gpg context"), NULL; + + if (homedir != NULL) + { + gpgme_engine_info_t info; + + info = gpgme_ctx_get_engine_info (context); + + if ((err = gpgme_ctx_set_engine_info (context, info->protocol, NULL, homedir)) + != GPG_ERR_NO_ERROR) + return ot_gpgme_throw (err, error, "Unable to set gpg homedir to '%s'", homedir), NULL; + } + + return g_steal_pointer (&context); +} + +static gboolean +get_gnupg_version (guint *major, + guint *minor, + guint *patch) +{ + g_return_val_if_fail (major != NULL, FALSE); + g_return_val_if_fail (minor != NULL, FALSE); + g_return_val_if_fail (patch != NULL, FALSE); + + gpgme_engine_info_t info; + gpgme_error_t err = gpgme_get_engine_info (&info); + if (err != GPG_ERR_NO_ERROR) + { + g_debug ("Failed to get GPGME engine info: %s: %s", + gpgme_strsource (err), gpgme_strerror (err)); + return FALSE; + } + + const char *gnupg_version = NULL; + for (; info != NULL; info = info->next) + { + if (info->protocol == GPGME_PROTOCOL_OpenPGP) + { + gnupg_version = info->version; + break; + } + } + + if (gnupg_version == NULL) + { + g_debug ("Could not determine GnuPG version"); + return FALSE; + } + + g_auto(GStrv) parts = g_strsplit (gnupg_version, ".", 4); + if (g_strv_length (parts) < 3) + { + g_debug ("Less than 3 components in GnuPG version \"%s\"", gnupg_version); + return FALSE; + } + + *major = g_ascii_strtoull (parts[0], NULL, 10); + *minor = g_ascii_strtoull (parts[1], NULL, 10); + *patch = g_ascii_strtoull (parts[2], NULL, 10); + + return TRUE; +} + +void +ot_gpgme_kill_agent (const char *homedir) +{ + g_return_if_fail (homedir != NULL); + + /* If gnupg is at least 2.1.17, gpg-agent will exit when the homedir + * is deleted. + */ + guint gnupg_major = 0, gnupg_minor = 0, gnupg_patch = 0; + if (get_gnupg_version (&gnupg_major, &gnupg_minor, &gnupg_patch)) + { + if ((gnupg_major > 2) || + (gnupg_major == 2 && gnupg_minor > 1) || + (gnupg_major == 2 && gnupg_minor == 1 && gnupg_patch >= 17)) + { + /* Note early return */ + g_debug ("GnuPG >= 2.1.17, skipping gpg-agent cleanup in %s", homedir); + return; + } + } + + /* Run gpg-connect-agent killagent /bye */ + g_autoptr(GPtrArray) argv = g_ptr_array_new (); + g_ptr_array_add (argv, "gpg-connect-agent"); + g_ptr_array_add (argv, "--homedir"); + g_ptr_array_add (argv, (gpointer)homedir); + g_ptr_array_add (argv, "killagent"); + g_ptr_array_add (argv, "/bye"); + g_ptr_array_add (argv, NULL); + + g_autoptr(GError) local_error = NULL; + GSpawnFlags flags = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL; + gint proc_status = 0; + g_autofree gchar *proc_stderr = NULL; + g_debug ("Killing gpg-agent in %s", homedir); + if (!g_spawn_sync (NULL, (char **)argv->pdata, NULL, flags, NULL, NULL, + NULL, &proc_stderr, &proc_status, &local_error)) + { + g_debug ("Spawning gpg-connect-agent failed: %s", local_error->message); + return; + } + if (!g_spawn_check_exit_status (proc_status, &local_error)) + { + /* Dump out stderr on failures */ + g_printerr ("%s", proc_stderr); + + g_debug ("Killing GPG agent with gpg-connect-agent failed: %s", + local_error->message); + return; + } +} diff --git a/src/libotutil/ot-gpg-utils.h b/src/libotutil/ot-gpg-utils.h new file mode 100644 index 0000000..e8a240b --- /dev/null +++ b/src/libotutil/ot-gpg-utils.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include +#include "libglnx.h" + +G_BEGIN_DECLS + +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_data_t, gpgme_data_release, NULL) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_ctx_t, gpgme_release, NULL) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_key_t, gpgme_key_unref, NULL) + +gboolean ot_gpgme_throw (gpgme_error_t gpg_error, GError **error, + const char *fmt, ...) G_GNUC_PRINTF (3, 4); + +gboolean ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, + char **out_tmp_home_dir, + GOutputStream **out_pubring_stream, + GCancellable *cancellable, + GError **error); + +gpgme_data_t ot_gpgme_data_input (GInputStream *input_stream); +gpgme_data_t ot_gpgme_data_output (GOutputStream *output_stream); + +gpgme_ctx_t ot_gpgme_new_ctx (const char *homedir, + GError **error); + +void ot_gpgme_kill_agent (const char *homedir); + +G_END_DECLS diff --git a/src/libotutil/ot-keyfile-utils.c b/src/libotutil/ot-keyfile-utils.c new file mode 100644 index 0000000..3e028b2 --- /dev/null +++ b/src/libotutil/ot-keyfile-utils.c @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "otutil.h" + +#include + +static gboolean +is_notfound (GError *error) +{ + return g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND) + || g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND); +} + +gboolean +ot_keyfile_get_boolean_with_default (GKeyFile *keyfile, + const char *section, + const char *value, + gboolean default_value, + gboolean *out_bool, + GError **error) +{ + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (section != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + GError *temp_error = NULL; + gboolean ret_bool = g_key_file_get_boolean (keyfile, section, value, &temp_error); + if (temp_error) + { + if (is_notfound (temp_error)) + { + g_clear_error (&temp_error); + ret_bool = default_value; + } + else + { + g_propagate_error (error, temp_error); + return FALSE; + } + } + + *out_bool = ret_bool; + return TRUE; +} + +gboolean +ot_keyfile_get_value_with_default (GKeyFile *keyfile, + const char *section, + const char *value, + const char *default_value, + char **out_value, + GError **error) +{ + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (section != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + GError *temp_error = NULL; + g_autofree char *ret_value = g_key_file_get_value (keyfile, section, value, &temp_error); + if (temp_error) + { + if (is_notfound (temp_error)) + { + g_clear_error (&temp_error); + g_assert (ret_value == NULL); + ret_value = g_strdup (default_value); + } + else + { + g_propagate_error (error, temp_error); + return FALSE; + } + } + + ot_transfer_out_value(out_value, &ret_value); + return TRUE; +} + +gboolean +ot_keyfile_get_value_with_default_group_optional (GKeyFile *keyfile, + const char *section, + const char *value, + const char *default_value, + char **out_value, + GError **error) +{ + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (section != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + GError *local_error = NULL; + g_autofree char *ret_value = NULL; + if (!ot_keyfile_get_value_with_default (keyfile, section, value, default_value, &ret_value, &local_error)) + { + if (g_error_matches (local_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) + { + g_clear_error (&local_error); + ret_value = g_strdup (default_value); + } + else + { + g_propagate_error (error, local_error); + return FALSE; + } + } + + ot_transfer_out_value(out_value, &ret_value); + return TRUE; +} + +/* Read the value of key as a string. If the value string contains + * zero or one of the separators and none of the others, read the + * string as a NULL-terminated array out_value. If the value string + * contains multiple of the separators, give an error. + * + * Returns TRUE on success, FALSE on error. */ +gboolean +ot_keyfile_get_string_list_with_separator_choice (GKeyFile *keyfile, + const char *section, + const char *key, + const char *separators, + char ***out_value, + GError **error) +{ + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (section != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (separators != NULL, FALSE); + + g_autofree char *value_str = NULL; + if (!ot_keyfile_get_value_with_default (keyfile, section, key, NULL, + &value_str, error)) + return FALSE; + + g_auto(GStrv) value_list = NULL; + if (value_str) + { + gchar sep = '\0'; + guint sep_count = 0; + for (size_t i = 0; i < strlen (separators) && sep_count <= 1; i++) + { + if (strchr (value_str, separators[i])) + { + sep_count++; + sep = separators[i]; + } + } + + if (sep_count == 0) + { + value_list = g_new (gchar *, 2); + value_list[0] = g_steal_pointer (&value_str); + value_list[1] = NULL; + } + else if (sep_count == 1) + { + if (!ot_keyfile_get_string_list_with_default (keyfile, section, key, + sep, NULL, &value_list, error)) + return FALSE; + } + else + { + return glnx_throw (error, "key value list contains more than one separator"); + } + } + + ot_transfer_out_value (out_value, &value_list); + return TRUE; +} + +gboolean +ot_keyfile_get_string_list_with_default (GKeyFile *keyfile, + const char *section, + const char *key, + char separator, + char **default_value, + char ***out_value, + GError **error) +{ + g_autoptr(GError) temp_error = NULL; + + g_return_val_if_fail (keyfile != NULL, FALSE); + g_return_val_if_fail (section != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + g_key_file_set_list_separator (keyfile, separator); + + g_auto(GStrv) ret_value = g_key_file_get_string_list (keyfile, section, + key, NULL, &temp_error); + + if (temp_error) + { + if (is_notfound (temp_error)) + { + g_clear_error (&temp_error); + ret_value = g_strdupv (default_value); + } + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + return FALSE; + } + } + + ot_transfer_out_value (out_value, &ret_value); + return TRUE; +} + +gboolean +ot_keyfile_copy_group (GKeyFile *source_keyfile, + GKeyFile *target_keyfile, + const char *group_name) +{ + g_auto(GStrv) keys = NULL; + gsize length, ii; + gboolean ret = FALSE; + + g_return_val_if_fail (source_keyfile != NULL, ret); + g_return_val_if_fail (target_keyfile != NULL, ret); + g_return_val_if_fail (group_name != NULL, ret); + + keys = g_key_file_get_keys (source_keyfile, group_name, &length, NULL); + + if (keys == NULL) + goto out; + + for (ii = 0; ii < length; ii++) + { + g_autofree char *value = NULL; + + value = g_key_file_get_value (source_keyfile, group_name, keys[ii], NULL); + g_key_file_set_value (target_keyfile, group_name, keys[ii], value); + } + + ret = TRUE; + + out: + return ret; +} diff --git a/src/libotutil/ot-keyfile-utils.h b/src/libotutil/ot-keyfile-utils.h new file mode 100644 index 0000000..b16571d --- /dev/null +++ b/src/libotutil/ot-keyfile-utils.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2011 Colin Walters . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean +ot_keyfile_get_boolean_with_default (GKeyFile *keyfile, + const char *section, + const char *value, + gboolean default_value, + gboolean *out_bool, + GError **error); + + +gboolean +ot_keyfile_get_value_with_default (GKeyFile *keyfile, + const char *section, + const char *value, + const char *default_value, + char **out_value, + GError **error); + +gboolean +ot_keyfile_get_value_with_default_group_optional (GKeyFile *keyfile, + const char *section, + const char *value, + const char *default_value, + char **out_value, + GError **error); + +gboolean +ot_keyfile_get_string_list_with_separator_choice (GKeyFile *keyfile, + const char *section, + const char *key, + const char *separators, + char ***out_value_list, + GError **error); + +gboolean +ot_keyfile_get_string_list_with_default (GKeyFile *keyfile, + const char *section, + const char *key, + char separator, + char **default_value, + char ***out_value, + GError **error); + +gboolean +ot_keyfile_copy_group (GKeyFile *source_keyfile, + GKeyFile *target_keyfile, + const char *group_name); + +G_END_DECLS diff --git a/src/libotutil/ot-opt-utils.c b/src/libotutil/ot-opt-utils.c new file mode 100644 index 0000000..5d55d8d --- /dev/null +++ b/src/libotutil/ot-opt-utils.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include + +#include + +#include "otutil.h" + +void +ot_util_usage_error (GOptionContext *context, const char *message, GError **error) +{ + gchar *help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s\n", help); + g_free (help); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, message); +} diff --git a/src/libotutil/ot-opt-utils.h b/src/libotutil/ot-opt-utils.h new file mode 100644 index 0000000..bac1b4e --- /dev/null +++ b/src/libotutil/ot-opt-utils.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 Colin Walters . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +void ot_util_usage_error (GOptionContext *context, const char *message, GError **error); + +G_END_DECLS diff --git a/src/libotutil/ot-tool-util.c b/src/libotutil/ot-tool-util.c new file mode 100644 index 0000000..35e6a34 --- /dev/null +++ b/src/libotutil/ot-tool-util.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" +#include "ot-tool-util.h" + +gboolean +ot_parse_boolean (const char *value, + gboolean *out_parsed, + GError **error) +{ +#define ARG_EQ(x, y) (g_ascii_strcasecmp(x, y) == 0) + if (ARG_EQ(value, "1") + || ARG_EQ(value, "true") + || ARG_EQ(value, "yes")) + *out_parsed = TRUE; + else if (ARG_EQ(value, "0") + || ARG_EQ(value, "false") + || ARG_EQ(value, "no") + || ARG_EQ(value, "none")) + *out_parsed = FALSE; + else + { + return glnx_throw (error, "Invalid boolean argument '%s'", value); + } + + return TRUE; +} + +gboolean +ot_parse_keyvalue (const char *keyvalue, + char **out_key, + char **out_value, + GError **error) +{ + const char *eq = strchr (keyvalue, '='); + if (!eq) + { + return glnx_throw (error, "Missing '=' in KEY=VALUE for --set"); + } + *out_key = g_strndup (keyvalue, eq - keyvalue); + *out_value = g_strdup (eq + 1); + return TRUE; +} + +/** + * Note: temporarily copied from GLib: https://github.com/GNOME/glib/blob/a419146578a42c760cff684292465b38df855f75/glib/garray.c#L1664 + * See documentation at: https://developer.gnome.org/glib/stable/glib-Pointer-Arrays.html#g-ptr-array-find-with-equal-func + * + * ot_ptr_array_find_with_equal_func: (skip) + * @haystack: pointer array to be searched + * @needle: pointer to look for + * @equal_func: (nullable): the function to call for each element, which should + * return %TRUE when the desired element is found; or %NULL to use pointer + * equality + * @index_: (optional) (out caller-allocates): return location for the index of + * the element, if found + * + * Checks whether @needle exists in @haystack, using the given @equal_func. + * If the element is found, %TRUE is returned and the element’s index is + * returned in @index_ (if non-%NULL). Otherwise, %FALSE is returned and @index_ + * is undefined. If @needle exists multiple times in @haystack, the index of + * the first instance is returned. + * + * @equal_func is called with the element from the array as its first parameter, + * and @needle as its second parameter. If @equal_func is %NULL, pointer + * equality is used. + * + * Returns: %TRUE if @needle is one of the elements of @haystack + * Since: 2.54 + */ +gboolean +ot_ptr_array_find_with_equal_func (GPtrArray *haystack, + gconstpointer needle, + GEqualFunc equal_func, + guint *index_) +{ + guint i; + + g_return_val_if_fail (haystack != NULL, FALSE); + + if (equal_func == NULL) + equal_func = g_direct_equal; + + for (i = 0; i < haystack->len; i++) + { + if (equal_func (g_ptr_array_index (haystack, i), needle)) + { + if (index_ != NULL) + *index_ = i; + return TRUE; + } + } + + return FALSE; +} diff --git a/src/libotutil/ot-tool-util.h b/src/libotutil/ot-tool-util.h new file mode 100644 index 0000000..70f7d55 --- /dev/null +++ b/src/libotutil/ot-tool-util.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean +ot_parse_boolean (const char *value, + gboolean *out_parsed, + GError **error); +gboolean +ot_parse_keyvalue (const char *keyvalue, + char **out_key, + char **out_value, + GError **error); +gboolean +ot_ptr_array_find_with_equal_func (GPtrArray *haystack, + gconstpointer needle, + GEqualFunc equal_func, + guint *index_); + +G_END_DECLS diff --git a/src/libotutil/ot-unix-utils.c b/src/libotutil/ot-unix-utils.c new file mode 100644 index 0000000..17016ae --- /dev/null +++ b/src/libotutil/ot-unix-utils.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "otutil.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* Ensure that a pathname component @name does not contain the special Unix + * entries `.` or `..`, and does not contain `/`. + */ +gboolean +ot_util_filename_validate (const char *name, + GError **error) +{ + if (name == NULL) + return glnx_throw (error, "Invalid NULL filename"); + if (strcmp (name, ".") == 0) + return glnx_throw (error, "Invalid self-referential filename '.'"); + if (strcmp (name, "..") == 0) + return glnx_throw (error, "Invalid path uplink filename '..'"); + if (strchr (name, '/') != NULL) + return glnx_throw (error, "Invalid / in filename %s", name); + if (!g_utf8_validate (name, -1, NULL)) + return glnx_throw (error, "Invalid UTF-8 in filename %s", name); + return TRUE; +} + +static GPtrArray * +ot_split_string_ptrarray (const char *str, + char c) +{ + GPtrArray *ret = g_ptr_array_new_with_free_func (g_free); + + const char *p; + do { + p = strchr (str, '/'); + if (!p) + { + g_ptr_array_add (ret, g_strdup (str)); + str = NULL; + } + else + { + g_ptr_array_add (ret, g_strndup (str, p - str)); + str = p + 1; + } + } while (str && *str); + + return ret; +} + +/* Given a pathname @path, split it into individual entries in @out_components, + * validating that it does not have backreferences (`..`) etc. + */ +gboolean +ot_util_path_split_validate (const char *path, + GPtrArray **out_components, + GError **error) +{ + if (strlen (path) > PATH_MAX) + return glnx_throw (error, "Path '%s' is too long", path); + + g_autoptr(GPtrArray) ret_components = ot_split_string_ptrarray (path, '/'); + + /* Canonicalize by removing '.' and '', throw an error on .. */ + for (int i = ret_components->len-1; i >= 0; i--) + { + const char *name = ret_components->pdata[i]; + if (strcmp (name, "..") == 0) + return glnx_throw (error, "Invalid uplink '..' in path %s", path); + if (strcmp (name, ".") == 0 || name[0] == '\0') + g_ptr_array_remove_index (ret_components, i); + } + + ot_transfer_out_value(out_components, &ret_components); + return TRUE; +} diff --git a/src/libotutil/ot-unix-utils.h b/src/libotutil/ot-unix-utils.h new file mode 100644 index 0000000..36e2f0a --- /dev/null +++ b/src/libotutil/ot-unix-utils.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011 Colin Walters . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include + +/* I just put all this shit here. Sue me. */ +#include +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +gboolean ot_util_filename_validate (const char *name, GError **error); + +gboolean ot_util_path_split_validate (const char *path, GPtrArray **out_components, GError **error); + +G_END_DECLS diff --git a/src/libotutil/ot-variant-builder.c b/src/libotutil/ot-variant-builder.c new file mode 100644 index 0000000..6636068 --- /dev/null +++ b/src/libotutil/ot-variant-builder.c @@ -0,0 +1,1216 @@ +/* + * Copyright (C) 2017 Alexander Larsson . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson . + */ + +#include "config.h" + +#include "ot-variant-builder.h" +#include "libglnx/libglnx.h" + +/***************************************************************************************** + * This code is copied from gvariant in glib. With the following copyright: + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Copyright © 2007, 2008 Ryan Lortie + * Copyright © 2010 Codethink Limited + *****************************************************************************************/ + +typedef struct _GVariantTypeInfo GVariantTypeInfo; + +#define G_VARIANT_TYPE_INFO_CHAR_MAYBE 'm' +#define G_VARIANT_TYPE_INFO_CHAR_ARRAY 'a' +#define G_VARIANT_TYPE_INFO_CHAR_TUPLE '(' +#define G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY '{' +#define G_VARIANT_TYPE_INFO_CHAR_VARIANT 'v' +#define g_variant_type_info_get_type_char(info) \ + (g_variant_type_info_get_type_string(info)[0]) + +struct _GVariantTypeInfo +{ + gsize fixed_size; + guchar alignment; + guchar container_class; +}; + +typedef struct +{ + GVariantTypeInfo *type_info; + + gsize i, a; + gint8 b, c; + + guint8 ending_type; +} GVariantMemberInfo; + +#define G_VARIANT_MEMBER_ENDING_FIXED 0 +#define G_VARIANT_MEMBER_ENDING_LAST 1 +#define G_VARIANT_MEMBER_ENDING_OFFSET 2 + +typedef struct +{ + GVariantTypeInfo info; + + gchar *type_string; + gint ref_count; +} ContainerInfo; + +typedef struct +{ + ContainerInfo container; + + GVariantTypeInfo *element; +} ArrayInfo; + +typedef struct +{ + ContainerInfo container; + + GVariantMemberInfo *members; + gsize n_members; +} TupleInfo; + +/* Hard-code the base types in a constant array */ +static const GVariantTypeInfo g_variant_type_info_basic_table[24] = { +#define fixed_aligned(x) x, x - 1 +#define not_a_type 0, +#define unaligned 0, 0 +#define aligned(x) 0, x - 1 + /* 'b' */ { fixed_aligned(1) }, /* boolean */ + /* 'c' */ { not_a_type }, + /* 'd' */ { fixed_aligned(8) }, /* double */ + /* 'e' */ { not_a_type }, + /* 'f' */ { not_a_type }, + /* 'g' */ { unaligned }, /* signature string */ + /* 'h' */ { fixed_aligned(4) }, /* file handle (int32) */ + /* 'i' */ { fixed_aligned(4) }, /* int32 */ + /* 'j' */ { not_a_type }, + /* 'k' */ { not_a_type }, + /* 'l' */ { not_a_type }, + /* 'm' */ { not_a_type }, + /* 'n' */ { fixed_aligned(2) }, /* int16 */ + /* 'o' */ { unaligned }, /* object path string */ + /* 'p' */ { not_a_type }, + /* 'q' */ { fixed_aligned(2) }, /* uint16 */ + /* 'r' */ { not_a_type }, + /* 's' */ { unaligned }, /* string */ + /* 't' */ { fixed_aligned(8) }, /* uint64 */ + /* 'u' */ { fixed_aligned(4) }, /* uint32 */ + /* 'v' */ { aligned(8) }, /* variant */ + /* 'w' */ { not_a_type }, + /* 'x' */ { fixed_aligned(8) }, /* int64 */ + /* 'y' */ { fixed_aligned(1) }, /* byte */ +#undef fixed_aligned +#undef not_a_type +#undef unaligned +#undef aligned +}; + +static GRecMutex g_variant_type_info_lock; +static GHashTable *g_variant_type_info_table; + +static GVariantTypeInfo * g_variant_type_info_ref (GVariantTypeInfo *info); +static void g_variant_type_info_unref (GVariantTypeInfo *info); +static GVariantTypeInfo * g_variant_type_info_get (const GVariantType *type); + +#define GV_ARRAY_INFO_CLASS 'a' +static ArrayInfo * +GV_ARRAY_INFO (GVariantTypeInfo *info) +{ + return (ArrayInfo *) info; +} + +static void +array_info_free (GVariantTypeInfo *info) +{ + ArrayInfo *array_info; + + g_assert (info->container_class == GV_ARRAY_INFO_CLASS); + array_info = (ArrayInfo *) info; + + g_variant_type_info_unref (array_info->element); + g_slice_free (ArrayInfo, array_info); +} + +static ContainerInfo * +array_info_new (const GVariantType *type) +{ + ArrayInfo *info; + + info = g_slice_new (ArrayInfo); + info->container.info.container_class = GV_ARRAY_INFO_CLASS; + + info->element = g_variant_type_info_get (g_variant_type_element (type)); + info->container.info.alignment = info->element->alignment; + info->container.info.fixed_size = 0; + + return (ContainerInfo *) info; +} + +/* == tuple == */ +#define GV_TUPLE_INFO_CLASS 'r' +static TupleInfo * +GV_TUPLE_INFO (GVariantTypeInfo *info) +{ + return (TupleInfo *) info; +} + +static void +tuple_info_free (GVariantTypeInfo *info) +{ + TupleInfo *tuple_info; + gint i; + + g_assert (info->container_class == GV_TUPLE_INFO_CLASS); + tuple_info = (TupleInfo *) info; + + for (i = 0; i < tuple_info->n_members; i++) + g_variant_type_info_unref (tuple_info->members[i].type_info); + + g_slice_free1 (sizeof (GVariantMemberInfo) * tuple_info->n_members, + tuple_info->members); + g_slice_free (TupleInfo, tuple_info); +} + +static void +tuple_allocate_members (const GVariantType *type, + GVariantMemberInfo **members, + gsize *n_members) +{ + const GVariantType *item_type; + gsize i = 0; + + *n_members = g_variant_type_n_items (type); + *members = g_slice_alloc (sizeof (GVariantMemberInfo) * *n_members); + + item_type = g_variant_type_first (type); + while (item_type) + { + GVariantMemberInfo *member = &(*members)[i++]; + + member->type_info = g_variant_type_info_get (item_type); + item_type = g_variant_type_next (item_type); + + if (member->type_info->fixed_size) + member->ending_type = G_VARIANT_MEMBER_ENDING_FIXED; + else if (item_type == NULL) + member->ending_type = G_VARIANT_MEMBER_ENDING_LAST; + else + member->ending_type = G_VARIANT_MEMBER_ENDING_OFFSET; + } + + g_assert (i == *n_members); +} + +/* this is g_variant_type_info_query for a given member of the tuple. + * before the access is done, it is ensured that the item is within + * range and %FALSE is returned if not. + */ +static gboolean +tuple_get_item (TupleInfo *info, + GVariantMemberInfo *item, + gsize *d, + gsize *e) +{ + if (&info->members[info->n_members] == item) + return FALSE; + + *d = item->type_info->alignment; + *e = item->type_info->fixed_size; + return TRUE; +} + +/* Read the documentation for #GVariantMemberInfo in gvarianttype.h + * before attempting to understand this. + * + * This function adds one set of "magic constant" values (for one item + * in the tuple) to the table. + * + * The algorithm in tuple_generate_table() calculates values of 'a', 'b' + * and 'c' for each item, such that the procedure for finding the item + * is to start at the end of the previous variable-sized item, add 'a', + * then round up to the nearest multiple of 'b', then add 'c'. + * Note that 'b' is stored in the usual "one less than" form. ie: + * + * start = ROUND_UP(prev_end + a, (b + 1)) + c; + * + * We tweak these values a little to allow for a slightly easier + * computation and more compact storage. + */ +static void +tuple_table_append (GVariantMemberInfo **items, + gsize i, + gsize a, + gsize b, + gsize c) +{ + GVariantMemberInfo *item = (*items)++; + + /* We can shift multiples of the alignment size from 'c' into 'a'. + * As long as we're shifting whole multiples, it won't affect the + * result. This means that we can take the "aligned" portion off of + * 'c' and add it into 'a'. + * + * Imagine (for sake of clarity) that ROUND_10 rounds up to the + * nearest 10. It is clear that: + * + * ROUND_10(a) + c == ROUND_10(a + 10*(c / 10)) + (c % 10) + * + * ie: remove the 10s portion of 'c' and add it onto 'a'. + * + * To put some numbers on it, imagine we start with a = 34 and c = 27: + * + * ROUND_10(34) + 27 = 40 + 27 = 67 + * + * but also, we can split 27 up into 20 and 7 and do this: + * + * ROUND_10(34 + 20) + 7 = ROUND_10(54) + 7 = 60 + 7 = 67 + * ^^ ^ + * without affecting the result. We do that here. + * + * This reduction in the size of 'c' means that we can store it in a + * gchar instead of a gsize. Due to how the structure is packed, this + * ends up saving us 'two pointer sizes' per item in each tuple when + * allocating using GSlice. + */ + a += ~b & c; /* take the "aligned" part of 'c' and add to 'a' */ + c &= b; /* chop 'c' to contain only the unaligned part */ + + + /* Finally, we made one last adjustment. Recall: + * + * start = ROUND_UP(prev_end + a, (b + 1)) + c; + * + * Forgetting the '+ c' for the moment: + * + * ROUND_UP(prev_end + a, (b + 1)); + * + * we can do a "round up" operation by adding 1 less than the amount + * to round up to, then rounding down. ie: + * + * #define ROUND_UP(x, y) ROUND_DOWN(x + (y-1), y) + * + * Of course, for rounding down to a power of two, we can just mask + * out the appropriate number of low order bits: + * + * #define ROUND_DOWN(x, y) (x & ~(y - 1)) + * + * Which gives us + * + * #define ROUND_UP(x, y) (x + (y - 1) & ~(y - 1)) + * + * but recall that our alignment value 'b' is already "one less". + * This means that to round 'prev_end + a' up to 'b' we can just do: + * + * ((prev_end + a) + b) & ~b + * + * Associativity, and putting the 'c' back on: + * + * (prev_end + (a + b)) & ~b + c + * + * Now, since (a + b) is constant, we can just add 'b' to 'a' now and + * store that as the number to add to prev_end. Then we use ~b as the + * number to take a bitwise 'and' with. Finally, 'c' is added on. + * + * Note, however, that all the low order bits of the 'aligned' value + * are masked out and that all of the high order bits of 'c' have been + * "moved" to 'a' (in the previous step). This means that there are + * no overlapping bits in the addition -- so we can do a bitwise 'or' + * equivalently. + * + * This means that we can now compute the start address of a given + * item in the tuple using the algorithm given in the documentation + * for #GVariantMemberInfo: + * + * item_start = ((prev_end + a) & b) | c; + */ + + item->i = i; + item->a = a + b; + item->b = ~b; + item->c = c; +} + +static gsize +tuple_align (gsize offset, + guint alignment) +{ + return offset + ((-offset) & alignment); +} + +/* This function is the heart of the algorithm for calculating 'i', 'a', + * 'b' and 'c' for each item in the tuple. + * + * Imagine we want to find the start of the "i" in the type "(su(qx)ni)". + * That's a string followed by a uint32, then a tuple containing a + * uint16 and a int64, then an int16, then our "i". In order to get to + * our "i" we: + * + * Start at the end of the string, align to 4 (for the uint32), add 4. + * Align to 8, add 16 (for the tuple). Align to 2, add 2 (for the + * int16). Then we're there. It turns out that, given 3 simple rules, + * we can flatten this iteration into one addition, one alignment, then + * one more addition. + * + * The loop below plays through each item in the tuple, querying its + * alignment and fixed_size into 'd' and 'e', respectively. At all + * times the variables 'a', 'b', and 'c' are maintained such that in + * order to get to the current point, you add 'a', align to 'b' then add + * 'c'. 'b' is kept in "one less than" form. For each item, the proper + * alignment is applied to find the values of 'a', 'b' and 'c' to get to + * the start of that item. Those values are recorded into the table. + * The fixed size of the item (if applicable) is then added on. + * + * These 3 rules are how 'a', 'b' and 'c' are modified for alignment and + * addition of fixed size. They have been proven correct but are + * presented here, without proof: + * + * 1) in order to "align to 'd'" where 'd' is less than or equal to the + * largest level of alignment seen so far ('b'), you align 'c' to + * 'd'. + * 2) in order to "align to 'd'" where 'd' is greater than the largest + * level of alignment seen so far, you add 'c' aligned to 'b' to the + * value of 'a', set 'b' to 'd' (ie: increase the 'largest alignment + * seen') and reset 'c' to 0. + * 3) in order to "add 'e'", just add 'e' to 'c'. + */ +static void +tuple_generate_table (TupleInfo *info) +{ + GVariantMemberInfo *items = info->members; + gsize i = -1, a = 0, b = 0, c = 0, d, e; + + /* iterate over each item in the tuple. + * 'd' will be the alignment of the item (in one-less form) + * 'e' will be the fixed size (or 0 for variable-size items) + */ + while (tuple_get_item (info, items, &d, &e)) + { + /* align to 'd' */ + if (d <= b) + c = tuple_align (c, d); /* rule 1 */ + else + a += tuple_align (c, b), b = d, c = 0; /* rule 2 */ + + /* the start of the item is at this point (ie: right after we + * have aligned for it). store this information in the table. + */ + tuple_table_append (&items, i, a, b, c); + + /* "move past" the item by adding in its size. */ + if (e == 0) + /* variable size: + * + * we'll have an offset stored to mark the end of this item, so + * just bump the offset index to give us a new starting point + * and reset all the counters. + */ + i++, a = b = c = 0; + else + /* fixed size */ + c += e; /* rule 3 */ + } +} + +static void +tuple_set_base_info (TupleInfo *info) +{ + GVariantTypeInfo *base = &info->container.info; + + if (info->n_members > 0) + { + GVariantMemberInfo *m; + + /* the alignment requirement of the tuple is the alignment + * requirement of its largest item. + */ + base->alignment = 0; + for (m = info->members; m < &info->members[info->n_members]; m++) + /* can find the max of a list of "one less than" powers of two + * by 'or'ing them + */ + base->alignment |= m->type_info->alignment; + + m--; /* take 'm' back to the last item */ + + /* the structure only has a fixed size if no variable-size + * offsets are stored and the last item is fixed-sized too (since + * an offset is never stored for the last item). + */ + if (m->i == -1 && m->type_info->fixed_size) + /* in that case, the fixed size can be found by finding the + * start of the last item (in the usual way) and adding its + * fixed size. + * + * if a tuple has a fixed size then it is always a multiple of + * the alignment requirement (to make packing into arrays + * easier) so we round up to that here. + */ + base->fixed_size = + tuple_align (((m->a & m->b) | m->c) + m->type_info->fixed_size, + base->alignment); + else + /* else, the tuple is not fixed size */ + base->fixed_size = 0; + } + else + { + /* the empty tuple: '()'. + * + * has a size of 1 and an no alignment requirement. + * + * It has a size of 1 (not 0) for two practical reasons: + * + * 1) So we can determine how many of them are in an array + * without dividing by zero or without other tricks. + * + * 2) Even if we had some trick to know the number of items in + * the array (as GVariant did at one time) this would open a + * potential denial of service attack: an attacker could send + * you an extremely small array (in terms of number of bytes) + * containing trillions of zero-sized items. If you iterated + * over this array you would effectively infinite-loop your + * program. By forcing a size of at least one, we bound the + * amount of computation done in response to a message to a + * reasonable function of the size of that message. + */ + base->alignment = 0; + base->fixed_size = 1; + } +} + +static ContainerInfo * +tuple_info_new (const GVariantType *type) +{ + TupleInfo *info; + + info = g_slice_new (TupleInfo); + info->container.info.container_class = GV_TUPLE_INFO_CLASS; + + tuple_allocate_members (type, &info->members, &info->n_members); + tuple_generate_table (info); + tuple_set_base_info (info); + + return (ContainerInfo *) info; +} + +static const GVariantMemberInfo * +g_variant_type_info_member_info (GVariantTypeInfo *info, + gsize index) +{ + TupleInfo *tuple_info = GV_TUPLE_INFO (info); + + if (index < tuple_info->n_members) + return &tuple_info->members[index]; + + return NULL; +} + +static GVariantTypeInfo * +g_variant_type_info_element (GVariantTypeInfo *info) +{ + return GV_ARRAY_INFO (info)->element; +} + +static GVariantTypeInfo * +g_variant_type_info_ref (GVariantTypeInfo *info) +{ + if (info->container_class) + { + ContainerInfo *container = (ContainerInfo *) info; + + g_assert_cmpint (container->ref_count, >, 0); + g_atomic_int_inc (&container->ref_count); + } + + return info; +} + +static void +g_variant_type_info_unref (GVariantTypeInfo *info) +{ + if (info->container_class) + { + ContainerInfo *container = (ContainerInfo *) info; + + g_rec_mutex_lock (&g_variant_type_info_lock); + if (g_atomic_int_dec_and_test (&container->ref_count)) + { + g_hash_table_remove (g_variant_type_info_table, + container->type_string); + if (g_hash_table_size (g_variant_type_info_table) == 0) + { + g_hash_table_unref (g_variant_type_info_table); + g_variant_type_info_table = NULL; + } + g_rec_mutex_unlock (&g_variant_type_info_lock); + + g_free (container->type_string); + + if (info->container_class == GV_ARRAY_INFO_CLASS) + array_info_free (info); + + else if (info->container_class == GV_TUPLE_INFO_CLASS) + tuple_info_free (info); + + else + g_assert_not_reached (); + } + else + g_rec_mutex_unlock (&g_variant_type_info_lock); + } +} + +static GVariantTypeInfo * +g_variant_type_info_get (const GVariantType *type) +{ + char type_char; + + type_char = g_variant_type_peek_string (type)[0]; + + if (type_char == G_VARIANT_TYPE_INFO_CHAR_MAYBE || + type_char == G_VARIANT_TYPE_INFO_CHAR_ARRAY || + type_char == G_VARIANT_TYPE_INFO_CHAR_TUPLE || + type_char == G_VARIANT_TYPE_INFO_CHAR_DICT_ENTRY) + { + GVariantTypeInfo *info; + gchar *type_string; + + type_string = g_variant_type_dup_string (type); + + g_rec_mutex_lock (&g_variant_type_info_lock); + + if (g_variant_type_info_table == NULL) + g_variant_type_info_table = g_hash_table_new (g_str_hash, + g_str_equal); + info = g_hash_table_lookup (g_variant_type_info_table, type_string); + + if (info == NULL) + { + ContainerInfo *container; + + if (type_char == G_VARIANT_TYPE_INFO_CHAR_MAYBE || + type_char == G_VARIANT_TYPE_INFO_CHAR_ARRAY) + { + container = array_info_new (type); + } + else /* tuple or dict entry */ + { + container = tuple_info_new (type); + } + + info = (GVariantTypeInfo *) container; + container->type_string = type_string; + container->ref_count = 1; + + g_hash_table_insert (g_variant_type_info_table, type_string, info); + type_string = NULL; + } + else + g_variant_type_info_ref (info); + + g_rec_mutex_unlock (&g_variant_type_info_lock); + g_free (type_string); + + return info; + } + else + { + const GVariantTypeInfo *info; + int index; + + index = type_char - 'b'; + g_assert (G_N_ELEMENTS (g_variant_type_info_basic_table) == 24); + g_assert_cmpint (0, <=, index); + g_assert_cmpint (index, <, 24); + + info = g_variant_type_info_basic_table + index; + + return (GVariantTypeInfo *) info; + } +} + +static inline void +gvs_write_unaligned_le (guchar *bytes, + gsize value, + guint size) +{ + union + { + guchar bytes[GLIB_SIZEOF_SIZE_T]; + gsize integer; + } tmpvalue; + + tmpvalue.integer = GSIZE_TO_LE (value); + memcpy (bytes, &tmpvalue.bytes, size); +} + +static guint +gvs_get_offset_size (gsize size) +{ + if (size > G_MAXUINT32) + return 8; + + else if (size > G_MAXUINT16) + return 4; + + else if (size > G_MAXUINT8) + return 2; + + else if (size > 0) + return 1; + + return 0; +} + +static gsize +gvs_calculate_total_size (gsize body_size, + gsize offsets) +{ + if (body_size + 1 * offsets <= G_MAXUINT8) + return body_size + 1 * offsets; + + if (body_size + 2 * offsets <= G_MAXUINT16) + return body_size + 2 * offsets; + + if (body_size + 4 * offsets <= G_MAXUINT32) + return body_size + 4 * offsets; + + return body_size + 8 * offsets; +} + + +/***************************************************************************************** + * End of glib code + *****************************************************************************************/ + +typedef struct _OtVariantBuilderInfo OtVariantBuilderInfo; + +struct _OtVariantBuilderInfo { + OtVariantBuilderInfo *parent; + OtVariantBuilder *builder; + GVariantType *type; + GVariantTypeInfo *type_info; + guint64 offset; + int n_children; + GArray *child_ends; + + /* type constraint explicitly specified by 'type'. + * for tuple types, this moves along as we add more items. + */ + const GVariantType *expected_type; + + /* type constraint implied by previous array item. + */ + const GVariantType *prev_item_type; + GVariantType *prev_item_type_base; + + /* constraints on the number of children. max = -1 for unlimited. */ + gsize min_items; + gsize max_items; + + /* set to '1' if all items in the container will have the same type + * (ie: maybe, array, variant) '0' if not (ie: tuple, dict entry) + */ + guint uniform_item_types : 1; +} ; + +struct _OtVariantBuilder { + gint ref_count; + int fd; + + /* This is only useful for the topmost builder and points to the top + * of the builder stack. Public APIs take the topmost builder reference + * and use this to find the currently active builder */ + OtVariantBuilderInfo *head; +}; + +static OtVariantBuilderInfo * +ot_variant_builder_info_new (OtVariantBuilder *builder, const GVariantType *type) +{ + OtVariantBuilderInfo *info; + + info = (OtVariantBuilderInfo *) g_slice_new0 (OtVariantBuilderInfo); + + g_return_val_if_fail (g_variant_type_is_container (type), NULL); + + info->builder = builder; + info->type = g_variant_type_copy (type); + info->type_info = g_variant_type_info_get (type); + info->offset = 0; + info->n_children = 0; + info->child_ends = g_array_new (FALSE, TRUE, sizeof (guint64)); + + switch (*(const gchar *) type) + { + case G_VARIANT_CLASS_VARIANT: + info->uniform_item_types = TRUE; + info->expected_type = NULL; + info->min_items = 1; + info->max_items = 1; + break; + + case G_VARIANT_CLASS_ARRAY: + info->uniform_item_types = TRUE; + info->expected_type = + g_variant_type_element (info->type); + info->min_items = 0; + info->max_items = -1; + break; + + case G_VARIANT_CLASS_MAYBE: + info->uniform_item_types = TRUE; + info->expected_type = + g_variant_type_element (info->type); + info->min_items = 0; + info->max_items = 1; + break; + + case G_VARIANT_CLASS_DICT_ENTRY: + info->uniform_item_types = FALSE; + info->expected_type = + g_variant_type_key (info->type); + info->min_items = 2; + info->max_items = 2; + break; + + case 'r': /* G_VARIANT_TYPE_TUPLE was given */ + info->uniform_item_types = FALSE; + info->expected_type = NULL; + info->min_items = 0; + info->max_items = -1; + break; + + case G_VARIANT_CLASS_TUPLE: /* a definite tuple type was given */ + info->expected_type = + g_variant_type_first (info->type); + info->min_items = g_variant_type_n_items (type); + info->max_items = info->min_items; + info->uniform_item_types = FALSE; + break; + + default: + g_assert_not_reached (); + } + + return info; +} + +static void +ot_variant_builder_info_free (OtVariantBuilderInfo *info) +{ + if (info->parent) + ot_variant_builder_info_free (info); + + g_variant_type_free (info->type); + g_array_unref (info->child_ends); + g_free (info->prev_item_type_base); + + g_slice_free (OtVariantBuilderInfo, info); +} + +OtVariantBuilder * +ot_variant_builder_new (const GVariantType *type, + int fd) +{ + OtVariantBuilder *builder; + + builder = (OtVariantBuilder *) g_slice_new0 (OtVariantBuilder); + + g_return_val_if_fail (g_variant_type_is_container (type), NULL); + + builder->head = ot_variant_builder_info_new (builder, type); + builder->ref_count = 1; + builder->fd = fd; + + return builder; +} + +void +ot_variant_builder_unref (OtVariantBuilder *builder) +{ + if (--builder->ref_count) + return; + + ot_variant_builder_info_free (builder->head); + + g_slice_free (OtVariantBuilder, builder); +} + +OtVariantBuilder * +ot_variant_builder_ref (OtVariantBuilder *builder) +{ + builder->ref_count++; + return builder; +} + +/* This is called before adding a child to the container. It updates + the internal state and does the needed alignment */ +static gboolean +ot_variant_builder_pre_add (OtVariantBuilderInfo *info, + const GVariantType *type, + GError **error) +{ + guint alignment = 0; + + if (!info->uniform_item_types) + { + /* advance our expected type pointers */ + if (info->expected_type) + info->expected_type = + g_variant_type_next (info->expected_type); + + if (info->prev_item_type) + info->prev_item_type = + g_variant_type_next (info->prev_item_type); + } + else + { + g_free (info->prev_item_type_base); + info->prev_item_type_base = (GVariantType *)g_strdup ((char *)type); + info->prev_item_type = info->prev_item_type_base; + } + + if (g_variant_type_is_tuple (info->type) || + g_variant_type_is_dict_entry (info->type)) + { + const GVariantMemberInfo *member_info; + + member_info = g_variant_type_info_member_info (info->type_info, info->n_children); + alignment = member_info->type_info->alignment; + } + else if (g_variant_type_is_array (info->type)) + { + GVariantTypeInfo *element_info = g_variant_type_info_element (info->type_info); + + alignment = element_info->alignment; + } + else if (g_variant_type_is_variant (info->type)) + { + alignment = info->type_info->alignment; + } + else + return glnx_throw (error, "adding to type %s not supported", (char *)info->type); + + while (info->offset & alignment) + { + if (glnx_loop_write (info->builder->fd, "\0", 1) < 0) + return glnx_throw_errno (error); + info->offset++; + } + + return TRUE; +} + +static void +ot_variant_builder_add_child_end (OtVariantBuilderInfo *info) +{ + guint64 v = info->offset; + g_array_append_val (info->child_ends, v); +} + +/* This is called after adding a child to the container. It + updates offset, n_children and keeps track of an offset + table if needed */ + +static gboolean +ot_variant_builder_post_add (OtVariantBuilderInfo *info, + const GVariantType *type, + guint64 bytes_added, + GError **error) +{ + info->offset += bytes_added; + + if (g_variant_type_is_tuple (info->type) || + g_variant_type_is_dict_entry (info->type)) + { + const GVariantMemberInfo *member_info; + + member_info = g_variant_type_info_member_info (info->type_info, info->n_children); + if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET) + ot_variant_builder_add_child_end (info); + } + else if (g_variant_type_is_array (info->type)) + { + GVariantTypeInfo *element_info = g_variant_type_info_element (info->type_info); + + if (!element_info->fixed_size) + ot_variant_builder_add_child_end (info); + } + else if (g_variant_type_is_variant (info->type)) + { + /* Zero separate */ + if (glnx_loop_write (info->builder->fd, "\0", 1) < 0) + return glnx_throw_errno (error); + + if (glnx_loop_write (info->builder->fd, (char *)type, strlen ((char *)type)) < 0) + return glnx_throw_errno (error); + + info->offset += 1 + strlen ((char *)type); + } + else + return glnx_throw (error, "adding to type %s not supported", (char *)info->type); + + info->n_children++; + + return TRUE; +} + +gboolean +ot_variant_builder_add_from_fd (OtVariantBuilder *builder, + const GVariantType *type, + int fd, + guint64 size, + GError **error) +{ + OtVariantBuilderInfo *info = builder->head; + + g_return_val_if_fail (info->n_children < info->max_items, + FALSE); + g_return_val_if_fail (!info->expected_type || + g_variant_type_is_subtype_of (type, + info->expected_type), + FALSE); + g_return_val_if_fail (!info->prev_item_type || + g_variant_type_is_subtype_of (info->prev_item_type, + type), + FALSE); + + if (!ot_variant_builder_pre_add (info, type, error)) + return FALSE; + + if (glnx_regfile_copy_bytes (fd, builder->fd, size) < 0) + return glnx_throw_errno (error); + + if (!ot_variant_builder_post_add (info, type, size, error)) + return FALSE; + + return TRUE; +} + +gboolean +ot_variant_builder_add_value (OtVariantBuilder *builder, + GVariant *value, + GError **error) +{ + OtVariantBuilderInfo *info = builder->head; + gconstpointer data; + gsize data_size; + /* We ref-sink value, just like g_variant_builder_add_value does */ + g_autoptr(GVariant) keep_around_until_return G_GNUC_UNUSED = g_variant_ref_sink (value); + + g_return_val_if_fail (info->n_children < info->max_items, + FALSE); + g_return_val_if_fail (!info->expected_type || + g_variant_is_of_type (value, + info->expected_type), + FALSE); + g_return_val_if_fail (!info->prev_item_type || + g_variant_is_of_type (value, + info->prev_item_type), + FALSE); + + if (!ot_variant_builder_pre_add (info, g_variant_get_type (value), error)) + return FALSE; + + data = g_variant_get_data (value); + data_size = g_variant_get_size (value); + + if (data) + { + if (glnx_loop_write (builder->fd, data, data_size) < 0) + return glnx_throw_errno (error); + } + + if (!ot_variant_builder_post_add (info, g_variant_get_type (value), data_size, error)) + return FALSE; + + return TRUE; +} + +gboolean +ot_variant_builder_add (OtVariantBuilder *builder, + GError **error, + const gchar *format_string, + ...) +{ + GVariant *variant; + va_list ap; + + va_start (ap, format_string); + variant = g_variant_new_va (format_string, NULL, &ap); + va_end (ap); + + return ot_variant_builder_add_value (builder, variant, error); +} + + +gboolean +ot_variant_builder_open (OtVariantBuilder *builder, + const GVariantType *type, + GError **error) +{ + OtVariantBuilderInfo *info = builder->head; + OtVariantBuilderInfo *new_info; + + g_return_val_if_fail (info->n_children < info->max_items, + FALSE); + g_return_val_if_fail (!info->expected_type || + g_variant_type_is_subtype_of (type, + info->expected_type), + FALSE); + g_return_val_if_fail (!info->prev_item_type || + g_variant_type_is_subtype_of (info->prev_item_type, + type), + FALSE); + + if (!ot_variant_builder_pre_add (info, type, error)) + return FALSE; + + new_info = ot_variant_builder_info_new (builder, type); + new_info->parent = info; + + /* push the prev_item_type down into the subcontainer */ + if (info->prev_item_type) + { + if (!new_info->uniform_item_types) + /* tuples and dict entries */ + new_info->prev_item_type = + g_variant_type_first (info->prev_item_type); + + else if (!g_variant_type_is_variant (new_info->type)) + /* maybes and arrays */ + new_info->prev_item_type = + g_variant_type_element (info->prev_item_type); + } + + builder->head = new_info; + return TRUE; +} + +gboolean +ot_variant_builder_close (OtVariantBuilder *builder, + GError **error) +{ + OtVariantBuilderInfo *info = builder->head; + OtVariantBuilderInfo *parent; + + g_return_val_if_fail (info->parent != NULL, FALSE); + + if (!ot_variant_builder_end (builder, error)) + return FALSE; + + parent = info->parent; + + if (!ot_variant_builder_post_add (parent, info->type, info->offset, error)) + return FALSE; + + builder->head = parent; + + info->parent = NULL; + ot_variant_builder_info_free (info); + + return TRUE; +} + +gboolean +ot_variant_builder_end (OtVariantBuilder *builder, + GError **error) +{ + OtVariantBuilderInfo *info = builder->head; + gboolean add_offset_table = FALSE; + gboolean reverse_offset_table = FALSE; + + g_return_val_if_fail (info->n_children >= info->min_items, + FALSE); + g_return_val_if_fail (!info->uniform_item_types || + info->prev_item_type != NULL || + g_variant_type_is_definite (info->type), + FALSE); + + if (g_variant_type_is_tuple (info->type) || + g_variant_type_is_dict_entry (info->type)) + { + add_offset_table = TRUE; + reverse_offset_table = TRUE; + } + else if (g_variant_type_is_array (info->type)) + { + GVariantTypeInfo *element_info = g_variant_type_info_element (info->type_info); + + if (!element_info->fixed_size) + add_offset_table = TRUE; + } + else if (g_variant_type_is_variant (info->type)) + { + /* noop */ + } + else + return glnx_throw (error, "closing type %s not supported", (char *)info->type); + + if (add_offset_table) + { + const gsize total_size = gvs_calculate_total_size (info->offset, info->child_ends->len); + const gsize offset_size = gvs_get_offset_size (total_size); + const gsize offset_table_size = total_size - info->offset; + g_autofree guchar *offset_table = g_malloc (offset_table_size); + guchar *p = offset_table; + if (reverse_offset_table) + { + for (int i = info->child_ends->len - 1; i >= 0; i--) + { + gvs_write_unaligned_le (p, g_array_index (info->child_ends, guint64, i), offset_size); + p += offset_size; + } + } + else + { + for (int i = 0; i < info->child_ends->len; i++) + { + gvs_write_unaligned_le (p, g_array_index (info->child_ends, guint64, i), offset_size); + p += offset_size; + } + } + + if (glnx_loop_write (builder->fd, offset_table, offset_table_size) < 0) + return glnx_throw_errno (error); + + info->offset += offset_table_size; + } + else + g_assert (info->child_ends->len == 0); + + return TRUE; +} diff --git a/src/libotutil/ot-variant-builder.h b/src/libotutil/ot-variant-builder.h new file mode 100644 index 0000000..8ea0a21 --- /dev/null +++ b/src/libotutil/ot-variant-builder.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 Alexander Larsson . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson . + */ + +#pragma once + +#include + +#include "libglnx.h" + +G_BEGIN_DECLS + +typedef struct _OtVariantBuilder OtVariantBuilder; + +OtVariantBuilder *ot_variant_builder_new (const GVariantType *type, + int fd); +void ot_variant_builder_unref (OtVariantBuilder *builder); +OtVariantBuilder *ot_variant_builder_ref (OtVariantBuilder *builder); +gboolean ot_variant_builder_end (OtVariantBuilder *builder, + GError **error); +gboolean ot_variant_builder_open (OtVariantBuilder *builder, + const GVariantType *type, + GError **error); +gboolean ot_variant_builder_close (OtVariantBuilder *builder, + GError **error); +gboolean ot_variant_builder_add_from_fd (OtVariantBuilder *builder, + const GVariantType *type, + int fd, + guint64 size, + GError **error); +gboolean ot_variant_builder_add_value (OtVariantBuilder *builder, + GVariant *value, + GError **error); +gboolean ot_variant_builder_add (OtVariantBuilder *builder, + GError **error, + const gchar *format_string, + ...); +void ot_variant_builder_add_parsed (OtVariantBuilder *builder, + const gchar *format, + ...); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OtVariantBuilder, ot_variant_builder_unref) + +G_END_DECLS diff --git a/src/libotutil/ot-variant-utils.c b/src/libotutil/ot-variant-utils.c new file mode 100644 index 0000000..fce3f53 --- /dev/null +++ b/src/libotutil/ot-variant-utils.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include + +#include + +#include "otutil.h" + +/* Create a new GVariant empty GVariant of type a{sv} */ +GVariant * +ot_gvariant_new_empty_string_dict (void) +{ + g_auto(GVariantBuilder) builder = OT_VARIANT_BUILDER_INITIALIZER; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + return g_variant_builder_end (&builder); +} + + +/* Create a new GVariant of type ay from the raw @data pointer */ +GVariant * +ot_gvariant_new_bytearray (const guchar *data, + gsize len) +{ + gpointer data_copy = g_memdup (data, len); + GVariant *ret = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data_copy, + len, FALSE, g_free, data_copy); + return ret; +} + +/* Convert a GBytes into a GVariant of type ay (byte array) */ +GVariant * +ot_gvariant_new_ay_bytes (GBytes *bytes) +{ + gsize size; + gconstpointer data = g_bytes_get_data (bytes, &size); + g_bytes_ref (bytes); + return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, size, + TRUE, (GDestroyNotify)g_bytes_unref, bytes); +} + +/* Create a GVariant in @out_variant that is backed by + * the data from @fd, starting at @start. If the data is + * large enough, mmap() may be used. @trusted is used + * by the GVariant core; see g_variant_new_from_data(). + */ +gboolean +ot_variant_read_fd (int fd, + goffset start, + const GVariantType *type, + gboolean trusted, + GVariant **out_variant, + GError **error) +{ + g_autoptr(GBytes) bytes = ot_fd_readall_or_mmap (fd, start, error); + if (!bytes) + return FALSE; + + *out_variant = g_variant_ref_sink (g_variant_new_from_bytes (type, bytes, trusted)); + return TRUE; +} + +/* GVariants are immutable; this function allows generating an open builder + * for a new variant, inherting the data from @variant. + */ +GVariantBuilder * +ot_util_variant_builder_from_variant (GVariant *variant, + const GVariantType *type) +{ + GVariantBuilder *builder = g_variant_builder_new (type); + + if (variant != NULL) + { + const int n = g_variant_n_children (variant); + for (int i = 0; i < n; i++) + { + g_autoptr(GVariant) child = g_variant_get_child_value (variant, i); + g_variant_builder_add_value (builder, child); + } + } + + return builder; +} + +/** + * ot_variant_bsearch_str: + * @array: A GVariant array whose first element must be a string + * @str: Search for this string + * @out_pos: Output position + * + * + * Binary search in a GVariant array, which must be of the form 'a(s...)', + * where '...' may be anything. The array elements must be sorted. + * + * Returns: %TRUE if found, %FALSE otherwise + */ +gboolean +ot_variant_bsearch_str (GVariant *array, + const char *str, + int *out_pos) +{ + const gsize n = g_variant_n_children (array); + if (n == 0) + return FALSE; + + gsize imax = n - 1; + gsize imin = 0; + gsize imid = -1; + while (imax >= imin) + { + const char *cur; + + imid = (imin + imax) / 2; + + g_autoptr(GVariant) child = g_variant_get_child_value (array, imid); + g_variant_get_child (child, 0, "&s", &cur, NULL); + + int cmp = strcmp (cur, str); + if (cmp < 0) + imin = imid + 1; + else if (cmp > 0) + { + if (imid == 0) + break; + imax = imid - 1; + } + else + { + *out_pos = imid; + return TRUE; + } + } + + *out_pos = imid; + return FALSE; +} diff --git a/src/libotutil/ot-variant-utils.h b/src/libotutil/ot-variant-utils.h new file mode 100644 index 0000000..d1cd8b5 --- /dev/null +++ b/src/libotutil/ot-variant-utils.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 Colin Walters . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +GVariant *ot_gvariant_new_bytearray (const guchar *data, + gsize len); + +GVariant *ot_gvariant_new_ay_bytes (GBytes *bytes); + +GVariant *ot_gvariant_new_empty_string_dict (void); + +gboolean ot_variant_read_fd (int fd, + goffset offset, + const GVariantType *type, + gboolean trusted, + GVariant **out_variant, + GError **error); + +GVariantBuilder *ot_util_variant_builder_from_variant (GVariant *variant, + const GVariantType *type); + +gboolean +ot_variant_bsearch_str (GVariant *array, + const char *str, + int *out_pos); + +G_END_DECLS diff --git a/src/libotutil/otutil.h b/src/libotutil/otutil.h new file mode 100644 index 0000000..cd31236 --- /dev/null +++ b/src/libotutil/otutil.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011 Colin Walters . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include +#include /* Yeah...let's just do that here. */ +#include + +/* https://bugzilla.gnome.org/show_bug.cgi?id=766370 */ +#if !GLIB_CHECK_VERSION(2, 49, 3) +#define OT_VARIANT_BUILDER_INITIALIZER {{0,}} +#else +#define OT_VARIANT_BUILDER_INITIALIZER {{{0,}}} +#endif + +#define ot_gobject_refz(o) (o ? g_object_ref (o) : o) + +#define ot_transfer_out_value(outp, srcp) G_STMT_START { \ + if (outp) \ + { \ + *outp = *srcp; \ + *(srcp) = NULL; \ + } \ + } G_STMT_END; + +#ifdef HAVE_LIBSYSTEMD +#define ot_journal_send(...) sd_journal_send(__VA_ARGS__) +#define ot_journal_print(...) sd_journal_print(__VA_ARGS__) +#else +#define ot_journal_send(...) {} +#define ot_journal_print(...) {} +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef OSTREE_DISABLE_GPGME +#include +#endif diff --git a/src/ostree/main.c b/src/ostree/main.c new file mode 100644 index 0000000..a9f5739 --- /dev/null +++ b/src/ostree/main.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include + +#include +#include +#include +#include + +#include "ot-main.h" +#include "ot-builtins.h" + +static OstreeCommand commands[] = { + /* Note: all admin related commands have + * no_repo as their command flag, but each + * admin command may have their own + * admin flag + */ + { "admin", OSTREE_BUILTIN_FLAG_NO_REPO, + ostree_builtin_admin, + "Commands for managing a host system booted with ostree" }, + { "cat", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_cat, + "Concatenate contents of files"}, + { "checkout", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_checkout, + "Check out a commit into a filesystem tree" }, + { "checksum", OSTREE_BUILTIN_FLAG_NO_REPO, + ostree_builtin_checksum, + "Checksum a file or directory" }, + { "commit", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_commit, + "Commit a new revision" }, + { "config", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_config, + "Change repo configuration settings" }, + { "diff", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_diff, + "Compare directory TARGETDIR against revision REV"}, + { "export", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_export, + "Stream COMMIT to stdout in tar format" }, + { "find-remotes", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_find_remotes, + "Find remotes to serve the given refs" }, + { "create-usb", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_create_usb, + "Copy the refs to a USB stick" }, + { "fsck", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_fsck, + "Check the repository for consistency" }, +#ifndef OSTREE_DISABLE_GPGME + { "gpg-sign", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_gpg_sign, + "Sign a commit" }, +#endif /* OSTREE_DISABLE_GPGME */ + { "init", OSTREE_BUILTIN_FLAG_NO_CHECK, + ostree_builtin_init, + "Initialize a new empty repository" }, + { "log", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_log, + "Show log starting at commit or ref" }, + { "ls", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_ls, + "List file paths" }, + { "prune", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_prune, + "Search for unreachable objects" }, + { "pull-local", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_pull_local, + "Copy data from SRC_REPO" }, +#ifdef HAVE_LIBCURL_OR_LIBSOUP + { "pull", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_pull, + "Download data from remote repository" }, +#endif + { "refs", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_refs, + "List refs" }, + { "remote", OSTREE_BUILTIN_FLAG_NO_REPO, + ostree_builtin_remote, + "Remote commands that may involve internet access" }, + { "reset", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_reset, + "Reset a REF to a previous COMMIT" }, + { "rev-parse", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_rev_parse, + "Output the target of a rev" }, + { "sign", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_sign, + "Sign a commit" }, + { "show", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_show, + "Output a metadata object" }, + { "static-delta", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_static_delta, + "Static delta related commands" }, + { "summary", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_summary, + "Manage summary metadata" }, +#if defined(HAVE_LIBSOUP) && defined(BUILDOPT_ENABLE_TRIVIAL_HTTPD_CMDLINE) + { "trivial-httpd", OSTREE_BUILTIN_FLAG_NONE, + ostree_builtin_trivial_httpd, + NULL }, +#endif + { NULL } +}; + +int +main (int argc, + char **argv) +{ + g_autoptr(GError) error = NULL; + int ret; + + setlocale (LC_ALL, ""); + + g_set_prgname (argv[0]); + + ret = ostree_run (argc, argv, commands, &error); + + if (error != NULL) + { + g_printerr ("%s%serror:%s%s %s\n", + ot_get_red_start (), ot_get_bold_start (), + ot_get_bold_end (), ot_get_red_end (), + error->message); + } + + return ret; +} diff --git a/src/ostree/ostree-trivial-httpd.c b/src/ostree/ostree-trivial-httpd.c new file mode 100644 index 0000000..a38abbe --- /dev/null +++ b/src/ostree/ostree-trivial-httpd.c @@ -0,0 +1,809 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +#include +#include +#include +#include +#include + +static char *opt_port_file = NULL; +static char *opt_log = NULL; +static gboolean opt_daemonize; +static gboolean opt_autoexit; +static gboolean opt_force_ranges; +static int opt_random_500s_percentage; +/* We have a strong upper bound for any unlikely + * cases involving repeated random 500s. */ +static int opt_random_500s_max = 100; +static int opt_random_408s_percentage; +static int opt_random_408s_max = 100; +static gint opt_port = 0; +static gchar **opt_expected_cookies; +static gchar **opt_expected_headers; +static gboolean opt_require_basic_auth; + +static guint emitted_random_500s_count = 0; +static guint emitted_random_408s_count = 0; + +typedef struct { + int root_dfd; + gboolean running; + GOutputStream *log; +} OtTrivialHttpd; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-trivial-httpd.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "daemonize", 'd', 0, G_OPTION_ARG_NONE, &opt_daemonize, "Fork into background when ready", NULL }, + { "autoexit", 0, 0, G_OPTION_ARG_NONE, &opt_autoexit, "Automatically exit when directory is deleted", NULL }, + { "port", 'P', 0, G_OPTION_ARG_INT, &opt_port, "Use the specified TCP port", "PORT" }, + { "port-file", 'p', 0, G_OPTION_ARG_FILENAME, &opt_port_file, "Write port number to PATH (- for standard output)", "PATH" }, + { "force-range-requests", 0, 0, G_OPTION_ARG_NONE, &opt_force_ranges, "Force range requests by only serving half of files", NULL }, + { "require-basic-auth", 0, 0, G_OPTION_ARG_NONE, &opt_require_basic_auth, "Require username foouser, password barpw", NULL }, + { "random-500s", 0, 0, G_OPTION_ARG_INT, &opt_random_500s_percentage, "Generate random HTTP 500 errors approximately for PERCENTAGE requests", "PERCENTAGE" }, + { "random-500s-max", 0, 0, G_OPTION_ARG_INT, &opt_random_500s_max, "Limit HTTP 500 errors to MAX (default 100)", "MAX" }, + { "random-408s", 0, 0, G_OPTION_ARG_INT, &opt_random_408s_percentage, "Generate random HTTP 408 errors approximately for PERCENTAGE requests", "PERCENTAGE" }, + { "random-408s-max", 0, 0, G_OPTION_ARG_INT, &opt_random_408s_max, "Limit HTTP 408 errors to MAX (default 100)", "MAX" }, + { "log-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_log, "Put logs here (use - for stdout)", "PATH" }, + { "expected-cookies", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_expected_cookies, "Expect given cookies in the http request", "KEY=VALUE" }, + { "expected-header", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_expected_headers, "Expect given headers in the http request", "KEY=VALUE" }, + { NULL } +}; + +static void +httpd_log (OtTrivialHttpd *httpd, const gchar *format, ...) __attribute__ ((format(printf, 2, 3))); + +static void +httpd_log (OtTrivialHttpd *httpd, const gchar *format, ...) +{ + g_autoptr(GString) str = NULL; + va_list args; + gsize written; + + if (!httpd->log) + return; + + { + g_autoptr(GDateTime) now = g_date_time_new_now_local (); + g_autofree char *timestamp = g_date_time_format (now, "%F %T"); + str = g_string_new (timestamp); + g_string_append_printf (str, ".%06d - ", g_date_time_get_microsecond (now)); + } + + va_start (args, format); + g_string_append_vprintf (str, format, args); + va_end (args); + + (void)g_output_stream_write_all (httpd->log, str->str, str->len, &written, NULL, NULL); +} + +static int +compare_strings (gconstpointer a, gconstpointer b) +{ + const char **sa = (const char **)a; + const char **sb = (const char **)b; + + return strcmp (*sa, *sb); +} + +static GString * +get_directory_listing (int dfd, + const char *path) +{ + g_autoptr(GPtrArray) entries = g_ptr_array_new_with_free_func (g_free); + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + guint i; + char *escaped; + GString *listing; + + listing = g_string_new ("\r\n"); + + if (!glnx_dirfd_iterator_init_at (dfd, path, FALSE, &dfd_iter, error)) + goto out; + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, NULL, error)) + goto out; + + if (dent == NULL) + break; + + escaped = g_markup_escape_text (dent->d_name, -1); + g_ptr_array_add (entries, escaped); + } + + g_ptr_array_sort (entries, (GCompareFunc)compare_strings); + + escaped = g_markup_escape_text (strchr (path, '/'), -1); + g_string_append_printf (listing, "Index of %s\r\n", escaped); + g_string_append_printf (listing, "

Index of %s

\r\n

\r\n", escaped); + g_free (escaped); + for (i = 0; i < entries->len; i++) + { + g_string_append_printf (listing, "%s
\r\n", + (char *)entries->pdata[i], + (char *)entries->pdata[i]); + g_free (g_steal_pointer (&entries->pdata[i])); + } + g_string_append (listing, "\r\n\r\n"); + out: + if (local_error) + g_printerr ("%s\n", local_error->message); + return listing; +} + +/* Only allow reading files that have o+r, and for directories, o+x. + * This makes this server relatively safe to use on multiuser + * machines. + */ +static gboolean +is_safe_to_access (struct stat *stbuf) +{ + /* Only regular files or directores */ + if (!(S_ISREG (stbuf->st_mode) || S_ISDIR (stbuf->st_mode))) + return FALSE; + /* Must be o+r */ + if (!(stbuf->st_mode & S_IROTH)) + return FALSE; + /* For directories, must be o+x */ + if (S_ISDIR (stbuf->st_mode) && !(stbuf->st_mode & S_IXOTH)) + return FALSE; + return TRUE; +} + +static void +close_socket (SoupMessage *msg, gpointer user_data) +{ + SoupSocket *sock = user_data; + int sockfd; + + /* Actually calling soup_socket_disconnect() here would cause + * us to leak memory, so just shutdown the socket instead. + */ + sockfd = soup_socket_get_fd (sock); +#ifdef G_OS_WIN32 + shutdown (sockfd, SD_SEND); +#else + shutdown (sockfd, SHUT_WR); +#endif +} + +static void +do_get (OtTrivialHttpd *self, + SoupServer *server, + SoupMessage *msg, + const char *path, + SoupClientContext *context) +{ + char *slash; + int ret; + struct stat stbuf; + + httpd_log (self, "serving %s\n", path); + + if (opt_expected_cookies) + { + GSList *cookies = soup_cookies_from_request (msg); + GSList *l; + int i; + + for (i = 0 ; opt_expected_cookies[i] != NULL; i++) + { + gboolean found = FALSE; + gchar *k = opt_expected_cookies[i]; + gchar *v = strchr (k, '=') + 1; + + for (l = cookies; l != NULL ; l = g_slist_next (l)) + { + SoupCookie *c = l->data; + + if (!strncmp (k, soup_cookie_get_name (c), v - k - 1) && + !strcmp (v, soup_cookie_get_value (c))) + { + found = TRUE; + break; + } + } + + if (!found) + { + httpd_log (self, "Expected cookie not found %s\n", k); + soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + soup_cookies_free (cookies); + goto out; + } + } + soup_cookies_free (cookies); + } + + if (opt_expected_headers) + { + for (int i = 0 ; opt_expected_headers[i] != NULL; i++) + { + const gchar *kv = opt_expected_headers[i]; + const gchar *eq = strchr (kv, '='); + + g_assert (eq); + + { + g_autofree char *k = g_strndup (kv, eq - kv); + const gchar *expected_v = eq + 1; + const gchar *found_v = soup_message_headers_get_one (msg->request_headers, k); + + if (!found_v) + { + httpd_log (self, "Expected header not found %s\n", k); + soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + goto out; + } + if (strcmp (found_v, expected_v) != 0) + { + httpd_log (self, "Expected header %s: %s but found %s\n", k, expected_v, found_v); + soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + goto out; + } + } + } + } + + if (strstr (path, "../") != NULL) + { + soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + goto out; + } + + if (opt_random_500s_percentage > 0 && + emitted_random_500s_count < opt_random_500s_max && + g_random_int_range (0, 100) < opt_random_500s_percentage) + { + emitted_random_500s_count++; + soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + goto out; + } + else if (opt_random_408s_percentage > 0 && + emitted_random_408s_count < opt_random_408s_max && + g_random_int_range (0, 100) < opt_random_408s_percentage) + { + emitted_random_408s_count++; + soup_message_set_status (msg, SOUP_STATUS_REQUEST_TIMEOUT); + goto out; + } + + while (path[0] == '/') + path++; + + do + ret = fstatat (self->root_dfd, path, &stbuf, 0); + while (ret == -1 && errno == EINTR); + if (ret == -1) + { + if (errno == EPERM) + soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + else if (errno == ENOENT) + soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); + else + soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + goto out; + } + + if (!is_safe_to_access (&stbuf)) + { + soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + goto out; + } + + if (S_ISDIR (stbuf.st_mode)) + { + slash = strrchr (path, '/'); + if (!slash || slash[1]) + { + g_autofree char *redir_uri = NULL; + + redir_uri = g_strdup_printf ("%s/", soup_message_get_uri (msg)->path); + soup_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY, + redir_uri); + } + else + { + g_autofree char *index_realpath = g_strconcat (path, "/index.html", NULL); + if (fstatat (self->root_dfd, index_realpath, &stbuf, 0) != -1) + { + g_autofree char *index_path = g_strconcat (path, "/index.html", NULL); + do_get (self, server, msg, index_path, context); + } + else + { + GString *listing = get_directory_listing (self->root_dfd, path); + soup_message_set_response (msg, "text/html", + SOUP_MEMORY_TAKE, + listing->str, listing->len); + soup_message_set_status (msg, SOUP_STATUS_OK); + g_string_free (listing, FALSE); + } + } + } + else + { + if (!S_ISREG (stbuf.st_mode)) + { + soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + goto out; + } + + if (msg->method == SOUP_METHOD_GET) + { + glnx_autofd int fd = -1; + g_autoptr(GMappedFile) mapping = NULL; + gsize buffer_length, file_size; + SoupRange *ranges; + int ranges_length; + gboolean have_ranges; + + fd = openat (self->root_dfd, path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + { + soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + goto out; + } + + mapping = g_mapped_file_new_from_fd (fd, FALSE, NULL); + if (!mapping) + { + soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + goto out; + } + (void) close (fd); fd = -1; + + file_size = g_mapped_file_get_length (mapping); + have_ranges = soup_message_headers_get_ranges(msg->request_headers, file_size, &ranges, &ranges_length); + if (opt_force_ranges && !have_ranges && g_strrstr (path, "/objects") != NULL) + { + SoupSocket *sock; + buffer_length = file_size/2; + soup_message_headers_set_content_length (msg->response_headers, file_size); + soup_message_headers_append (msg->response_headers, + "Connection", "close"); + + /* soup-message-io will wait for us to add + * another chunk after the first, to fill out + * the declared Content-Length. Instead, we + * forcibly close the socket at that point. + */ + sock = soup_client_context_get_socket (context); + g_signal_connect (msg, "wrote-chunk", G_CALLBACK (close_socket), sock); + } + else + buffer_length = file_size; + + if (have_ranges) + { + if (ranges_length > 0 && ranges[0].start >= file_size) + { + soup_message_set_status (msg, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE); + soup_message_headers_free_ranges (msg->request_headers, ranges); + goto out; + } + soup_message_headers_free_ranges (msg->request_headers, ranges); + } + if (buffer_length > 0) + { + SoupBuffer *buffer; + + buffer = soup_buffer_new_with_owner (g_mapped_file_get_contents (mapping), + buffer_length, + g_mapped_file_ref (mapping), + (GDestroyNotify)g_mapped_file_unref); + soup_message_body_append_buffer (msg->response_body, buffer); + soup_buffer_free (buffer); + } + } + else /* msg->method == SOUP_METHOD_HEAD */ + { + g_autofree char *length = NULL; + + /* We could just use the same code for both GET and + * HEAD (soup-message-server-io.c will fix things up). + * But we'll optimize and avoid the extra I/O. + */ + length = g_strdup_printf ("%lu", (gulong)stbuf.st_size); + soup_message_headers_append (msg->response_headers, + "Content-Length", length); + } + soup_message_set_status (msg, SOUP_STATUS_OK); + } + out: + { + guint status = 0; + g_autofree gchar *reason = NULL; + + g_object_get (msg, + "status-code", &status, + "reason-phrase", &reason, + NULL); + httpd_log (self, " status: %s (%u)\n", reason, status); + } + return; +} + +static void +httpd_callback (SoupServer *server, SoupMessage *msg, + const char *path, GHashTable *query, + SoupClientContext *context, gpointer data) +{ + OtTrivialHttpd *self = data; + + if (msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD) + do_get (self, server, msg, path, context); + else + soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); +} + +static gboolean +basic_auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, + const char *username, const char *password, gpointer data) +{ + return g_str_equal (username, "foouser") && g_str_equal (password, "barpw"); +} + +static void +on_dir_changed (GFileMonitor *mon, + GFile *file, + GFile *other, + GFileMonitorEvent event, + gpointer user_data) +{ + OtTrivialHttpd *self = user_data; + + if (event == G_FILE_MONITOR_EVENT_DELETED) + { + httpd_log (self, "root directory removed, exiting\n"); + self->running = FALSE; + g_main_context_wakeup (NULL); + } +} + +static gboolean +run (int argc, char **argv, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GOptionContext) context = NULL; + const char *dirpath; + OtTrivialHttpd appstruct = { 0, }; + OtTrivialHttpd *app = &appstruct; + int pipefd[2] = { -1, -1 }; + glnx_unref_object SoupServer *server = NULL; + g_autoptr(GFileMonitor) dirmon = NULL; + + context = g_option_context_new ("[DIR] - Simple webserver"); + g_option_context_add_main_entries (context, options, NULL); + + app->root_dfd = -1; + + if (!g_option_context_parse (context, &argc, &argv, error)) + goto out; + + if (argc > 1) + dirpath = argv[1]; + else + dirpath = "."; + + if (!glnx_opendirat (AT_FDCWD, dirpath, TRUE, &app->root_dfd, error)) + goto out; + + if (!(opt_random_500s_percentage >= 0 && opt_random_500s_percentage <= 99)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid --random-500s=%u", opt_random_500s_percentage); + goto out; + } + + if (!(opt_random_408s_percentage >= 0 && opt_random_408s_percentage <= 99)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid --random-408s=%u", opt_random_408s_percentage); + goto out; + } + + if (opt_daemonize && (g_strcmp0 (opt_log, "-") == 0)) + { + ot_util_usage_error (context, "Cannot use --log-file=- and --daemonize at the same time", error); + goto out; + } + + /* Fork early before glib sets up its worker context and thread since they'll + * be gone once the parent exits. The parent waits on a pipe with the child to + * handle setup errors. The child writes a 0 when setup is successful and a 1 + * otherwise. + */ + if (opt_daemonize) + { + if (pipe (pipefd) == -1) + { + glnx_set_error_from_errno (error); + goto out; + } + + pid_t pid = fork(); + if (pid == -1) + { + glnx_set_error_from_errno (error); + goto out; + } + else if (pid > 0) + { + /* Parent, read the child status from the pipe */ + glnx_close_fd (&pipefd[1]); + guint8 buf; + int res = TEMP_FAILURE_RETRY (read (pipefd[0], &buf, 1)); + if (res < 0) + { + glnx_set_error_from_errno (error); + goto out; + } + else if (res == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Child process closed pipe without writing status"); + goto out; + } + + g_debug ("Read %u from child", buf); + if (buf > 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Child process failed during setup"); + goto out; + } + glnx_close_fd (&pipefd[0]); + + ret = TRUE; + goto out; + } + + /* Child, continue */ + glnx_close_fd (&pipefd[0]); + } + else + { + /* Since we're used for testing purposes, let's just do this by + * default. This ensures we exit when our parent does. + */ + if (prctl (PR_SET_PDEATHSIG, SIGTERM) != 0) + { + if (errno != ENOSYS) + { + glnx_set_error_from_errno (error); + goto out; + } + } + } + + if (opt_log) + { + GOutputStream *stream = NULL; + + if (g_strcmp0 (opt_log, "-") == 0) + { + stream = G_OUTPUT_STREAM (g_unix_output_stream_new (STDOUT_FILENO, FALSE)); + } + else + { + g_autoptr(GFile) log_file = NULL; + GFileOutputStream* log_stream; + + log_file = g_file_new_for_path (opt_log); + log_stream = g_file_create (log_file, + G_FILE_CREATE_PRIVATE, + cancellable, + error); + if (!log_stream) + goto out; + stream = G_OUTPUT_STREAM (log_stream); + } + + app->log = stream; + } + +#if SOUP_CHECK_VERSION(2, 48, 0) + server = soup_server_new (SOUP_SERVER_SERVER_HEADER, "ostree-httpd ", NULL); + if (!soup_server_listen_all (server, opt_port, 0, error)) + goto out; +#else + server = soup_server_new (SOUP_SERVER_PORT, opt_port, + SOUP_SERVER_SERVER_HEADER, "ostree-httpd ", + NULL); +#endif + if (opt_require_basic_auth) + { + glnx_unref_object SoupAuthDomain *auth_domain = + soup_auth_domain_basic_new (SOUP_AUTH_DOMAIN_REALM, "auth-test", + SOUP_AUTH_DOMAIN_ADD_PATH, "/", + SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, basic_auth_callback, + NULL); + soup_server_add_auth_domain (server, auth_domain); + } + + soup_server_add_handler (server, NULL, httpd_callback, app, NULL); + if (opt_port_file) + { + g_autofree char *portstr = NULL; +#if SOUP_CHECK_VERSION(2, 48, 0) + GSList *listeners = soup_server_get_listeners (server); + g_autoptr(GSocket) listener = NULL; + g_autoptr(GSocketAddress) addr = NULL; + + g_assert (listeners); + listener = g_object_ref (listeners->data); + g_slist_free (listeners); + listeners = NULL; + addr = g_socket_get_local_address (listener, error); + if (!addr) + goto out; + + g_assert (G_IS_INET_SOCKET_ADDRESS (addr)); + + portstr = g_strdup_printf ("%u\n", g_inet_socket_address_get_port ((GInetSocketAddress*)addr)); +#else + portstr = g_strdup_printf ("%u\n", soup_server_get_port (server)); +#endif + + if (g_strcmp0 ("-", opt_port_file) == 0) + { + fputs (portstr, stdout); // not g_print - this must go to stdout, not a handler + fflush (stdout); + } + else if (!g_file_set_contents (opt_port_file, portstr, strlen (portstr), error)) + goto out; + } +#if !SOUP_CHECK_VERSION(2, 48, 0) + soup_server_run_async (server); +#endif + + if (opt_daemonize) + { + /* Write back a 0 to the pipe to indicate setup was successful. */ + guint8 buf = 0; + g_debug ("Writing %u to parent", buf); + if (TEMP_FAILURE_RETRY (write (pipefd[1], &buf, 1)) == -1) + { + glnx_set_error_from_errno (error); + goto out; + } + glnx_close_fd (&pipefd[1]); + + if (setsid () < 0) + { + glnx_set_prefix_error_from_errno (error, "%s", "setsid: "); + goto out; + } + /* Daemonising: close stdout/stderr so $() et al work on us */ + if (freopen("/dev/null", "r", stdin) == NULL) + { + glnx_set_prefix_error_from_errno (error, "%s", "freopen: "); + goto out; + } + if (freopen("/dev/null", "w", stdout) == NULL) + { + glnx_set_prefix_error_from_errno (error, "%s", "freopen: "); + goto out; + } + if (freopen("/dev/null", "w", stderr) == NULL) + { + glnx_set_prefix_error_from_errno (error, "%s", "freopen: "); + goto out; + } + } + + app->running = TRUE; + if (opt_autoexit) + { + gboolean is_symlink = FALSE; + g_autoptr(GFile) root = NULL; + g_autoptr(GFileInfo) info = NULL; + + root = g_file_new_for_path (dirpath); + info = g_file_query_info (root, + G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!info) + goto out; + + is_symlink = g_file_info_get_is_symlink (info); + + if (is_symlink) + dirmon = g_file_monitor_file (root, 0, cancellable, error); + else + dirmon = g_file_monitor_directory (root, 0, cancellable, error); + + if (!dirmon) + goto out; + g_signal_connect (dirmon, "changed", G_CALLBACK (on_dir_changed), app); + } + httpd_log (app, "serving at root %s\n", dirpath); + while (app->running) + g_main_context_iteration (NULL, TRUE); + + ret = TRUE; + out: + if (pipefd[0] >= 0) + { + /* Read end in the parent. This should only be open on errors. */ + g_assert_false (ret); + glnx_close_fd (&pipefd[0]); + } + if (pipefd[1] >= 0) + { + /* Write end in the child. This should only be open on errors. */ + g_assert_false (ret); + guint8 buf = 1; + g_debug ("Writing %u to parent", buf); + (void) TEMP_FAILURE_RETRY (write (pipefd[1], &buf, 1)); + glnx_close_fd (&pipefd[1]); + } + if (app->root_dfd != -1) + (void) close (app->root_dfd); + g_clear_object (&app->log); + return ret; +} + +int +main (int argc, + char **argv) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GCancellable) cancellable = NULL; + + setlocale (LC_ALL, ""); + + g_set_prgname (argv[0]); + + if (!run (argc, argv, cancellable, &error)) + { + g_printerr ("%s%serror:%s%s %s\n", + ot_get_red_start (), ot_get_bold_start (), + ot_get_bold_end (), ot_get_red_end (), + error->message); + return 1; + } + + return 0; +} diff --git a/src/ostree/ot-admin-builtin-cleanup.c b/src/ostree/ot-admin-builtin-cleanup.c new file mode 100644 index 0000000..875d6fa --- /dev/null +++ b/src/ostree/ot-admin-builtin-cleanup.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" + +#include + +static GOptionEntry options[] = { + { NULL } +}; + +gboolean +ot_admin_builtin_cleanup (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new (""); + + g_autoptr(OstreeSysroot) sysroot = NULL; + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, + invocation, &sysroot, cancellable, error)) + return FALSE; + + if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) + return FALSE; + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c new file mode 100644 index 0000000..bcece3f --- /dev/null +++ b/src/ostree/ot-admin-builtin-deploy.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2012,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "otutil.h" + +#include + +static gboolean opt_retain; +static gboolean opt_stage; +static gboolean opt_retain_pending; +static gboolean opt_retain_rollback; +static gboolean opt_not_as_default; +static gboolean opt_no_prune; +static gboolean opt_no_merge; +static char **opt_kernel_argv; +static char **opt_kernel_argv_append; +static gboolean opt_kernel_proc_cmdline; +static char *opt_osname; +static char *opt_origin_path; +static gboolean opt_kernel_arg_none; + +static GOptionEntry options[] = { + { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, + { "origin-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_origin_path, "Specify origin file", "FILENAME" }, + { "no-prune", 0, 0, G_OPTION_ARG_NONE, &opt_no_prune, "Don't prune the repo when done", NULL}, + { "no-merge", 0, 0, G_OPTION_ARG_NONE, &opt_no_merge, "Do not apply configuration (/etc and kernel arguments) from booted deployment", NULL}, + { "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployments", NULL }, + { "stage", 0, 0, G_OPTION_ARG_NONE, &opt_stage, "Complete deployment at OS shutdown", NULL }, + { "retain-pending", 0, 0, G_OPTION_ARG_NONE, &opt_retain_pending, "Do not delete pending deployments", NULL }, + { "retain-rollback", 0, 0, G_OPTION_ARG_NONE, &opt_retain_rollback, "Do not delete rollback deployments", NULL }, + { "not-as-default", 0, 0, G_OPTION_ARG_NONE, &opt_not_as_default, "Append rather than prepend new deployment", NULL }, + { "karg-proc-cmdline", 0, 0, G_OPTION_ARG_NONE, &opt_kernel_proc_cmdline, "Import current /proc/cmdline", NULL }, + { "karg", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv, "Set kernel argument, like root=/dev/sda1; this overrides any earlier argument with the same name", "NAME=VALUE" }, + { "karg-append", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv_append, "Append kernel argument; useful with e.g. console= that can be used multiple times", "NAME=VALUE" }, + { "karg-none", 0, 0, G_OPTION_ARG_NONE, &opt_kernel_arg_none, "Do not import kernel arguments", NULL }, + { NULL } +}; + +gboolean +ot_admin_builtin_deploy (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = + g_option_context_new ("REFSPEC"); + + g_autoptr(OstreeSysroot) sysroot = NULL; + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, + invocation, &sysroot, cancellable, error)) + return FALSE; + + if (argc < 2) + { + ot_util_usage_error (context, "REF/REV must be specified", error); + return FALSE; + } + + if (opt_kernel_proc_cmdline && opt_kernel_arg_none) + { + ot_util_usage_error (context, "Can't specify both --karg-proc-cmdline and --karg-none", error); + return FALSE; + } + + const char *refspec = argv[1]; + + OstreeRepo *repo = ostree_sysroot_repo (sysroot); + + /* Find the currently booted deployment, if any; we will ensure it + * is present in the new deployment list. + */ + if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, + cancellable, error)) + return glnx_prefix_error (error, "Looking for booted deployment"); + + g_autoptr(GKeyFile) origin = NULL; + if (opt_origin_path) + { + origin = g_key_file_new (); + + if (!g_key_file_load_from_file (origin, opt_origin_path, 0, error)) + return FALSE; + } + else + { + origin = ostree_sysroot_origin_new_from_refspec (sysroot, refspec); + } + + g_autofree char *revision = NULL; + if (!ostree_repo_resolve_rev (repo, refspec, FALSE, &revision, error)) + return FALSE; + + g_autoptr(OstreeDeployment) merge_deployment = + opt_no_merge ? NULL : ostree_sysroot_get_merge_deployment (sysroot, opt_osname); + + /* Here we perform cleanup of any leftover data from previous + * partial failures. This avoids having to call + * glnx_shutil_rm_rf_at() at random points throughout the process. + * + * TODO: Add /ostree/transaction file, and only do this cleanup if + * we find it. + */ + if (!ostree_sysroot_prepare_cleanup (sysroot, cancellable, error)) + return glnx_prefix_error (error, "Performing initial cleanup"); + + /* Initial set of kernel arguments; the default is to use the merge + * deployment, unless --karg-none or --karg-proc-cmdline are specified. + */ + g_autoptr(OstreeKernelArgs) kargs = NULL; + if (opt_kernel_arg_none) + { + kargs = ostree_kernel_args_new (); + } + else if (opt_kernel_proc_cmdline) + { + kargs = ostree_kernel_args_new (); + if (!ostree_kernel_args_append_proc_cmdline (kargs, cancellable, error)) + return FALSE; + } + else if (merge_deployment && (opt_kernel_argv || opt_kernel_argv_append)) + { + OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment); + g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1); + kargs = ostree_kernel_args_new (); + ostree_kernel_args_append_argv (kargs, previous_args); + } + + /* Now replace/extend the above set. Note that if no options are specified, + * we should end up passing NULL as override_kernel_argv for + * ostree_sysroot_deploy_tree() so we get the defaults. + */ + if (opt_kernel_argv) + { + if (!kargs) + kargs = ostree_kernel_args_new (); + ostree_kernel_args_replace_argv (kargs, opt_kernel_argv); + } + + if (opt_kernel_argv_append) + { + if (!kargs) + kargs = ostree_kernel_args_new (); + ostree_kernel_args_append_argv (kargs, opt_kernel_argv_append); + } + + g_autoptr(OstreeDeployment) new_deployment = NULL; + g_auto(GStrv) kargs_strv = kargs ? ostree_kernel_args_to_strv (kargs) : NULL; + if (opt_stage) + { + if (opt_retain_pending || opt_retain_rollback) + return glnx_throw (error, "--stage cannot currently be combined with --retain arguments"); + if (opt_not_as_default) + return glnx_throw (error, "--stage cannot currently be combined with --not-as-default"); + if (!ostree_sysroot_stage_tree (sysroot, opt_osname, revision, origin, merge_deployment, + kargs_strv, &new_deployment, cancellable, error)) + return FALSE; + g_assert (new_deployment); + } + else + { + if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin, merge_deployment, + kargs_strv, &new_deployment, cancellable, error)) + return FALSE; + g_assert (new_deployment); + + OstreeSysrootSimpleWriteDeploymentFlags flags = OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN; + if (opt_retain) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN; + else + { + if (opt_retain_pending) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING; + if (opt_retain_rollback) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK; + } + + if (opt_not_as_default) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT; + + if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, new_deployment, + merge_deployment, flags, cancellable, error)) + return FALSE; + } + + /* And finally, cleanup of any leftover data. In stage mode, we + * don't do a full cleanup as we didn't touch the bootloader. + */ + if (opt_no_prune || opt_stage) + { + if (!ostree_sysroot_prepare_cleanup (sysroot, cancellable, error)) + return FALSE; + } + else + { + if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) + return FALSE; + } + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-diff.c b/src/ostree/ot-admin-builtin-diff.c new file mode 100644 index 0000000..2785588 --- /dev/null +++ b/src/ostree/ot-admin-builtin-diff.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2012 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" + +#include + +static char *opt_osname; + +static GOptionEntry options[] = { + { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, + { NULL } +}; + +gboolean +ot_admin_builtin_diff (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new (""); + g_option_context_add_main_entries (context, options, NULL); + + g_autoptr(OstreeSysroot) sysroot = NULL; + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + invocation, &sysroot, cancellable, error)) + return FALSE; + + if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, + cancellable, error)) + return FALSE; + + g_autoptr(OstreeDeployment) deployment = NULL; + if (opt_osname != NULL) + { + deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname); + if (deployment == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No deployment for OS '%s'", opt_osname); + return FALSE; + } + } + else + deployment = g_object_ref (ostree_sysroot_get_booted_deployment (sysroot)); + + g_autoptr(GFile) deployment_dir = ostree_sysroot_get_deployment_directory (sysroot, deployment); + g_autoptr(GFile) orig_etc_path = g_file_resolve_relative_path (deployment_dir, "usr/etc"); + g_autoptr(GFile) new_etc_path = g_file_resolve_relative_path (deployment_dir, "etc"); + g_autoptr(GPtrArray) modified = g_ptr_array_new_with_free_func ((GDestroyNotify) ostree_diff_item_unref); + g_autoptr(GPtrArray) removed = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + g_autoptr(GPtrArray) added = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + if (!ostree_diff_dirs (OSTREE_DIFF_FLAGS_IGNORE_XATTRS, + orig_etc_path, new_etc_path, modified, removed, added, + cancellable, error)) + return FALSE; + + ostree_diff_print (orig_etc_path, new_etc_path, modified, removed, added); + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-finalize-staged.c b/src/ostree/ot-admin-builtin-finalize-staged.c new file mode 100644 index 0000000..3cea1bd --- /dev/null +++ b/src/ostree/ot-admin-builtin-finalize-staged.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "config.h" + +#include + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "otutil.h" + +#include "ostree-cmdprivate.h" +#include "ostree.h" + +static GOptionEntry options[] = { + { NULL } +}; + +/* Called by ostree-finalize-staged.service, and in turn + * invokes a cmdprivate function inside the shared library. + */ +gboolean +ot_admin_builtin_finalize_staged (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + /* Just a sanity check; we shouldn't be called outside of the service though. + */ + struct stat stbuf; + if (fstatat (AT_FDCWD, "/run/ostree-booted", &stbuf, 0) < 0) + return TRUE; + + g_autoptr(GOptionContext) context = g_option_context_new (""); + g_autoptr(OstreeSysroot) sysroot = NULL; + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, + invocation, &sysroot, cancellable, error)) + return FALSE; + + if (!ostree_cmd__private__()->ostree_finalize_staged (sysroot, cancellable, error)) + return FALSE; + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-init-fs.c b/src/ostree/ot-admin-builtin-init-fs.c new file mode 100644 index 0000000..cb1e1b6 --- /dev/null +++ b/src/ostree/ot-admin-builtin-init-fs.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2012 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "otutil.h" + +#include + +static gboolean opt_modern; + +static GOptionEntry options[] = { + { "modern", 0, 0, G_OPTION_ARG_NONE, &opt_modern, "Only create /boot and /ostree", NULL }, + { NULL } +}; + +gboolean +ot_admin_builtin_init_fs (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new ("PATH"); + + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | + OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED | + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, + invocation, NULL, cancellable, error)) + return FALSE; + + if (argc < 2) + { + ot_util_usage_error (context, "PATH must be specified", error); + return FALSE; + } + + const char *sysroot_path = argv[1]; + + glnx_autofd int root_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, sysroot_path, TRUE, &root_dfd, error)) + return FALSE; + + /* It's common to want to mount this outside of a deployment as well */ + if (!glnx_shutil_mkdir_p_at (root_dfd, "boot", 0755, cancellable, error)) + return FALSE; + + /* See https://github.com/coreos/coreos-assembler/pull/688 + * For Fedora CoreOS at least, we have this now to the point where we don't + * need this stuff in the physical sysroot. I'm not sure we ever really did, + * but to be conservative, make it opt-in to the new model of just boot/ and ostree/. + */ + if (!opt_modern) + { + const char *traditional_toplevels[] = {"boot", "dev", "home", "proc", "run", "sys"}; + for (guint i = 0; i < G_N_ELEMENTS (traditional_toplevels); i++) + { + if (!glnx_shutil_mkdir_p_at (root_dfd, traditional_toplevels[i], 0755, + cancellable, error)) + return FALSE; + } + + if (!glnx_shutil_mkdir_p_at (root_dfd, "root", 0700, + cancellable, error)) + return FALSE; + + if (!glnx_shutil_mkdir_p_at (root_dfd, "tmp", 01777, + cancellable, error)) + return FALSE; + if (fchmodat (root_dfd, "tmp", 01777, 0) == -1) + { + glnx_set_prefix_error_from_errno (error, "chmod: %s", "tmp"); + return FALSE; + } + } + + g_autoptr(GFile) dir = g_file_new_for_path (sysroot_path); + g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (dir); + if (!ostree_sysroot_ensure_initialized (sysroot, cancellable, error)) + return FALSE; + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-instutil.c b/src/ostree/ot-admin-builtin-instutil.c new file mode 100644 index 0000000..fe0d80a --- /dev/null +++ b/src/ostree/ot-admin-builtin-instutil.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2011,2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ot-admin-instutil-builtins.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" + +#include + +static OstreeCommand admin_instutil_subcommands[] = { +#ifdef HAVE_SELINUX + { "selinux-ensure-labeled", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_instutil_builtin_selinux_ensure_labeled, + "Relabel all or part of a deployment" }, +#endif + { "set-kargs", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_instutil_builtin_set_kargs, + "Set new kernel command line arguments(Not stable)" }, + { "grub2-generate", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_instutil_builtin_grub2_generate, + "Generate GRUB2 configuration from given BLS entries" }, + { NULL, 0, NULL, NULL } +}; + +static GOptionContext * +ostree_admin_instutil_option_context_new_with_commands (void) +{ + OstreeCommand *command = admin_instutil_subcommands; + GOptionContext *context = g_option_context_new ("COMMAND"); + + g_autoptr(GString) summary = g_string_new ("Builtin \"admin instutil\" Commands:"); + + while (command->name != NULL) + { + if ((command->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0) + { + g_string_append_printf (summary, "\n %-24s", command->name); + if (command->description != NULL) + g_string_append_printf (summary, "%s", command->description); + } + + command++; + } + + g_option_context_set_summary (context, summary->str); + + return context; +} + +gboolean +ot_admin_builtin_instutil (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + const char *subcommand_name = NULL; + int in, out; + + for (in = 1, out = 1; in < argc; in++, out++) + { + /* The non-option is the command, take it out of the arguments */ + if (argv[in][0] != '-') + { + if (subcommand_name == NULL) + { + subcommand_name = argv[in]; + out--; + continue; + } + } + + else if (g_str_equal (argv[in], "--")) + { + break; + } + + argv[out] = argv[in]; + } + + argc = out; + + OstreeCommand *subcommand = admin_instutil_subcommands; + while (subcommand->name) + { + if (g_strcmp0 (subcommand_name, subcommand->name) == 0) + break; + subcommand++; + } + + if (!subcommand->name) + { + g_autoptr(GOptionContext) context = + ostree_admin_instutil_option_context_new_with_commands (); + + /* This will not return for some options (e.g. --version). */ + if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, + invocation, NULL, cancellable, error)) + { + if (subcommand_name == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No \"admin instutil\" subcommand specified"); + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Unknown \"admin instutil\" subcommand '%s'", subcommand_name); + } + } + + g_autofree char *help = g_option_context_get_help (context, FALSE, NULL); + g_printerr ("%s", help); + return FALSE; + } + + g_autofree char *prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name); + g_set_prgname (prgname); + + OstreeCommandInvocation sub_invocation = { .command = subcommand }; + if (!subcommand->fn (argc, argv, &sub_invocation, cancellable, error)) + return FALSE; + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-os-init.c b/src/ostree/ot-admin-builtin-os-init.c new file mode 100644 index 0000000..203f297 --- /dev/null +++ b/src/ostree/ot-admin-builtin-os-init.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "otutil.h" + +#include + +static GOptionEntry options[] = { + { NULL } +}; + +gboolean +ot_admin_builtin_os_init (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + gboolean ret = FALSE; + const char *osname = NULL; + + context = g_option_context_new ("OSNAME"); + + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + invocation, &sysroot, cancellable, error)) + goto out; + + if (!ostree_sysroot_ensure_initialized (sysroot, cancellable, error)) + goto out; + + if (argc < 2) + { + ot_util_usage_error (context, "OSNAME must be specified", error); + goto out; + } + + osname = argv[1]; + + if (!ostree_sysroot_init_osname (sysroot, osname, cancellable, error)) + goto out; + + g_print ("ostree/deploy/%s initialized as OSTree root\n", osname); + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-admin-builtin-pin.c b/src/ostree/ot-admin-builtin-pin.c new file mode 100644 index 0000000..d4337e3 --- /dev/null +++ b/src/ostree/ot-admin-builtin-pin.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "otutil.h" + +static gboolean opt_unpin; + +static GOptionEntry options[] = { + { "unpin", 'u', 0, G_OPTION_ARG_NONE, &opt_unpin, "Unset pin", NULL }, + { NULL } +}; + +gboolean +ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new ("INDEX"); + g_autoptr(OstreeSysroot) sysroot = NULL; + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, + invocation, &sysroot, cancellable, error)) + return FALSE; + + if (argc < 2) + { + ot_util_usage_error (context, "INDEX must be specified", error); + return FALSE; + } + + for (unsigned int i = 1; i < argc; i++) + { + const char *deploy_index_str = argv[i]; + const int deploy_index = atoi (deploy_index_str); + + g_autoptr(OstreeDeployment) target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error); + if (!target_deployment) + return FALSE; + + gboolean current_pin = ostree_deployment_is_pinned (target_deployment); + const gboolean desired_pin = !opt_unpin; + if (current_pin == desired_pin) + { + g_print ("Deployment %s is already %s\n", deploy_index_str, current_pin ? "pinned" : "unpinned"); + } + else + { + if (!ostree_sysroot_deployment_set_pinned (sysroot, target_deployment, desired_pin, error)) + return FALSE; + g_print ("Deployment %s is now %s\n", deploy_index_str, desired_pin ? "pinned" : "unpinned"); + } + } + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-set-origin.c b/src/ostree/ot-admin-builtin-set-origin.c new file mode 100644 index 0000000..9d96512 --- /dev/null +++ b/src/ostree/ot-admin-builtin-set-origin.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2015 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "otutil.h" + +#include +#include +#include + +static int opt_index = -1; +static char **opt_set; + +static GOptionEntry options[] = { + { "set", 's', 0, G_OPTION_ARG_STRING_ARRAY, &opt_set, "Set config option KEY=VALUE for remote", "KEY=VALUE" }, + { "index", 0, 0, G_OPTION_ARG_INT, &opt_index, "Operate on the deployment INDEX, starting from zero", "INDEX" }, + { NULL } +}; + +gboolean +ot_admin_builtin_set_origin (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GOptionContext) context = NULL; + const char *remotename = NULL; + const char *url = NULL; + const char *branch = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + g_autoptr(OstreeDeployment) target_deployment = NULL; + + context = g_option_context_new ("REMOTENAME URL [BRANCH]"); + + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, + invocation, &sysroot, cancellable, error)) + goto out; + + if (argc < 3) + { + ot_util_usage_error (context, "REMOTENAME and URL must be specified", error); + goto out; + } + + remotename = argv[1]; + url = argv[2]; + if (argc > 3) + branch = argv[3]; + + if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) + goto out; + + if (opt_index == -1) + { + target_deployment = ostree_sysroot_get_booted_deployment (sysroot); + if (target_deployment == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Not currently booted into an OSTree system"); + goto out; + } + /* To match the below */ + target_deployment = g_object_ref (target_deployment); + } + else + { + target_deployment = ot_admin_get_indexed_deployment (sysroot, opt_index, error); + if (!target_deployment) + goto out; + } + + { char **iter; + g_autoptr(GVariantBuilder) optbuilder = + g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_autoptr(GVariant) options = NULL; + + for (iter = opt_set; iter && *iter; iter++) + { + const char *keyvalue = *iter; + g_autofree char *subkey = NULL; + g_autofree char *subvalue = NULL; + + if (!ot_parse_keyvalue (keyvalue, &subkey, &subvalue, error)) + goto out; + + g_variant_builder_add (optbuilder, "{s@v}", + subkey, g_variant_new_variant (g_variant_new_string (subvalue))); + } + + options = g_variant_ref_sink (g_variant_builder_end (optbuilder)); + + if (!ostree_repo_remote_change (repo, NULL, + OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS, + remotename, url, + options, + cancellable, error)) + goto out; + } + + { GKeyFile *old_origin = ostree_deployment_get_origin (target_deployment); + g_autofree char *origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL); + g_autofree char *origin_remote = NULL; + g_autofree char *origin_ref = NULL; + + if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error)) + goto out; + + { g_autofree char *new_refspec = g_strconcat (remotename, ":", branch ? branch : origin_ref, NULL); + g_autoptr(GKeyFile) new_origin = NULL; + + new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec); + + if (!ostree_sysroot_write_origin_file (sysroot, target_deployment, new_origin, + cancellable, error)) + goto out; + } + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-admin-builtin-status.c b/src/ostree/ot-admin-builtin-status.c new file mode 100644 index 0000000..c6c5238 --- /dev/null +++ b/src/ostree/ot-admin-builtin-status.c @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2012,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "libglnx.h" + +#include + +static GOptionEntry options[] = { + { NULL } +}; + +#ifndef OSTREE_DISABLE_GPGME +static gboolean +deployment_get_gpg_verify (OstreeDeployment *deployment, + OstreeRepo *repo) +{ + /* XXX Something like this could be added to the OstreeDeployment + * API in libostree if the OstreeRepo parameter is acceptable. */ + GKeyFile *origin = ostree_deployment_get_origin (deployment); + + if (origin == NULL) + return FALSE; + + g_autofree char *refspec = g_key_file_get_string (origin, "origin", "refspec", NULL); + + if (refspec == NULL) + return FALSE; + + g_autofree char *remote = NULL; + if (!ostree_parse_refspec (refspec, &remote, NULL, NULL)) + return FALSE; + + gboolean gpg_verify = FALSE; + if (remote) + (void) ostree_repo_remote_get_gpg_verify (repo, remote, &gpg_verify, NULL); + + return gpg_verify; +} +#endif /* OSTREE_DISABLE_GPGME */ + + +static gboolean +deployment_print_status (OstreeSysroot *sysroot, + OstreeRepo *repo, + OstreeDeployment *deployment, + gboolean is_booted, + gboolean is_pending, + gboolean is_rollback, + GCancellable *cancellable, + GError **error) +{ + const char *ref = ostree_deployment_get_csum (deployment); + + /* Load the backing commit; shouldn't normally fail, but if it does, + * we stumble on. + */ + g_autoptr(GVariant) commit = NULL; + (void)ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, ref, + &commit, NULL); + g_autoptr(GVariant) commit_metadata = NULL; + if (commit) + commit_metadata = g_variant_get_child_value (commit, 0); + + const char *version = NULL; + const char *source_title = NULL; + if (commit_metadata) + { + (void) g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_VERSION, "&s", &version); + (void) g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_SOURCE_TITLE, "&s", &source_title); + } + + GKeyFile *origin = ostree_deployment_get_origin (deployment); + + const char *deployment_status = ""; + if (ostree_deployment_is_staged (deployment)) + deployment_status = " (staged)"; + else if (is_pending) + deployment_status = " (pending)"; + else if (is_rollback) + deployment_status = " (rollback)"; + g_print ("%c %s %s.%d%s\n", + is_booted ? '*' : ' ', + ostree_deployment_get_osname (deployment), + ostree_deployment_get_csum (deployment), + ostree_deployment_get_deployserial (deployment), + deployment_status); + if (version) + g_print (" Version: %s\n", version); + + OstreeDeploymentUnlockedState unlocked = ostree_deployment_get_unlocked (deployment); + switch (unlocked) + { + case OSTREE_DEPLOYMENT_UNLOCKED_NONE: + break; + default: + g_print (" %s%sUnlocked: %s%s%s\n", ot_get_red_start (), ot_get_bold_start (), + ostree_deployment_unlocked_state_to_string (unlocked), + ot_get_bold_end (), ot_get_red_end ()); + } + if (ostree_deployment_is_pinned (deployment)) + g_print (" Pinned: yes\n"); + if (!origin) + g_print (" origin: none\n"); + else + { + g_autofree char *origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL); + if (!origin_refspec) + g_print (" origin: \n"); + else + g_print (" origin refspec: %s\n", origin_refspec); + if (source_title) + g_print (" `- %s\n", source_title); + } + +#ifndef OSTREE_DISABLE_GPGME + if (deployment_get_gpg_verify (deployment, repo)) + { + g_autoptr(GString) output_buffer = g_string_sized_new (256); + /* Print any digital signatures on this commit. */ + + const char *osname = ostree_deployment_get_osname (deployment); + g_autoptr(GError) local_error = NULL; + g_autoptr(OstreeGpgVerifyResult) result = + ostree_repo_verify_commit_for_remote (repo, ref, osname, + cancellable, &local_error); + + /* G_IO_ERROR_NOT_FOUND just means the commit is not signed. */ + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&local_error); + return TRUE; + } + else if (local_error != NULL) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + const guint n_signatures = ostree_gpg_verify_result_count_all (result); + for (guint jj = 0; jj < n_signatures; jj++) + { + ostree_gpg_verify_result_describe (result, jj, output_buffer, " GPG: ", + OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT); + } + + g_print ("%s", output_buffer->str); + } +#endif /* OSTREE_DISABLE_GPGME */ + + return TRUE; +} + +gboolean +ot_admin_builtin_status (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new (""); + + g_autoptr(OstreeSysroot) sysroot = NULL; + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + invocation, &sysroot, cancellable, error)) + return FALSE; + + g_autoptr(OstreeRepo) repo = NULL; + if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) + return FALSE; + + g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot); + OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + + g_autoptr(OstreeDeployment) pending_deployment = NULL; + g_autoptr(OstreeDeployment) rollback_deployment = NULL; + if (booted_deployment) + ostree_sysroot_query_deployments_for (sysroot, NULL, &pending_deployment, + &rollback_deployment); + + if (deployments->len == 0) + { + g_print ("No deployments.\n"); + } + else + { + for (guint i = 0; i < deployments->len; i++) + { + OstreeDeployment *deployment = deployments->pdata[i]; + if (!deployment_print_status (sysroot, repo, deployment, + deployment == booted_deployment, + deployment == pending_deployment, + deployment == rollback_deployment, + cancellable, + error)) + return FALSE; + } + } + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-switch.c b/src/ostree/ot-admin-builtin-switch.c new file mode 100644 index 0000000..2f12ef1 --- /dev/null +++ b/src/ostree/ot-admin-builtin-switch.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2012,2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "otutil.h" + +#include +#include +#include + +static gboolean opt_reboot; +static char *opt_osname; + +static GOptionEntry options[] = { + { "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Reboot after switching trees", NULL }, + { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, + { NULL } +}; + +gboolean +ot_admin_builtin_switch (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = + g_option_context_new ("REF"); + g_autoptr(OstreeSysroot) sysroot = NULL; + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, + invocation, &sysroot, cancellable, error)) + return FALSE; + + if (argc < 2) + { + ot_util_usage_error (context, "REF must be specified", error); + return FALSE; + } + + const char *new_provided_refspec = argv[1]; + + g_autoptr(OstreeSysrootUpgrader) upgrader = + ostree_sysroot_upgrader_new_for_os_with_flags (sysroot, opt_osname, + OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED, + cancellable, error); + if (!upgrader) + return FALSE; + + GKeyFile *old_origin = ostree_sysroot_upgrader_get_origin (upgrader); + g_autofree char *origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL); + g_autofree char *origin_remote = NULL; + g_autofree char *origin_ref = NULL; + if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error)) + return FALSE; + + g_autofree char *new_remote = NULL; + g_autofree char *new_ref = NULL; + /* Allow just switching remotes */ + if (g_str_has_suffix (new_provided_refspec, ":")) + { + new_remote = g_strdup (new_provided_refspec); + new_remote[strlen(new_remote)-1] = '\0'; + new_ref = g_strdup (origin_ref); + } + else + { + if (!ostree_parse_refspec (new_provided_refspec, &new_remote, &new_ref, error)) + return FALSE; + } + + const char* remote = new_remote ?: origin_remote; + g_autofree char *new_refspec = NULL; + if (remote) + new_refspec = g_strconcat (remote, ":", new_ref, NULL); + else + new_refspec = g_strdup (new_ref); + + if (strcmp (origin_refspec, new_refspec) == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Old and new refs are equal: %s", new_refspec); + return FALSE; + } + + g_autoptr(GKeyFile) new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec); + if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin, cancellable, error)) + return FALSE; + + { g_auto(GLnxConsoleRef) console = { 0, }; + glnx_console_lock (&console); + + g_autoptr(OstreeAsyncProgress) progress = NULL; + if (console.is_tty) + progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); + + /* Always allow older...there's not going to be a chronological + * relationship necessarily. + */ + gboolean changed; + if (!ostree_sysroot_upgrader_pull (upgrader, 0, + OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER, + progress, &changed, + cancellable, error)) + return FALSE; + + if (progress) + ostree_async_progress_finish (progress); + } + + if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error)) + return FALSE; + + OstreeRepo *repo = ostree_sysroot_repo (sysroot); + if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) + return FALSE; + + g_print ("Deleting ref '%s:%s'\n", origin_remote, origin_ref); + ostree_repo_transaction_set_ref (repo, origin_remote, origin_ref, NULL); + + if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) + return FALSE; + + if (opt_reboot) + { + if (!ot_admin_execve_reboot (sysroot, error)) + return FALSE; + } + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-undeploy.c b/src/ostree/ot-admin-builtin-undeploy.c new file mode 100644 index 0000000..0a50dc0 --- /dev/null +++ b/src/ostree/ot-admin-builtin-undeploy.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2012,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "otutil.h" + +static GOptionEntry options[] = { + { NULL } +}; + +gboolean +ot_admin_builtin_undeploy (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + const char *deploy_index_str; + int deploy_index; + g_autoptr(GPtrArray) current_deployments = NULL; + g_autoptr(OstreeDeployment) target_deployment = NULL; + + context = g_option_context_new ("INDEX"); + + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, + invocation, &sysroot, cancellable, error)) + return FALSE; + + if (argc < 2) + { + ot_util_usage_error (context, "INDEX must be specified", error); + return FALSE; + } + + current_deployments = ostree_sysroot_get_deployments (sysroot); + + deploy_index_str = argv[1]; + deploy_index = atoi (deploy_index_str); + + target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error); + if (!target_deployment) + return FALSE; + + if (target_deployment == ostree_sysroot_get_booted_deployment (sysroot)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Cannot undeploy currently booted deployment %i", deploy_index); + return FALSE; + } + + g_ptr_array_remove_index (current_deployments, deploy_index); + + if (!ostree_sysroot_write_deployments (sysroot, current_deployments, + cancellable, error)) + return FALSE; + + g_print ("Deleted deployment %s.%d\n", ostree_deployment_get_csum (target_deployment), + ostree_deployment_get_deployserial (target_deployment)); + + if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) + return glnx_prefix_error (error, "Performing final cleanup"); + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtin-unlock.c b/src/ostree/ot-admin-builtin-unlock.c new file mode 100644 index 0000000..cd46618 --- /dev/null +++ b/src/ostree/ot-admin-builtin-unlock.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "otutil.h" + +#include +#include + +static gboolean opt_hotfix; + +static GOptionEntry options[] = { + { "hotfix", 0, 0, G_OPTION_ARG_NONE, &opt_hotfix, "Retain changes across reboots", NULL }, + { NULL } +}; + +gboolean +ot_admin_builtin_unlock (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + OstreeDeployment *booted_deployment = NULL; + OstreeDeploymentUnlockedState target_state; + + context = g_option_context_new (""); + + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, + invocation, &sysroot, cancellable, error)) + goto out; + + if (argc > 1) + { + ot_util_usage_error (context, "This command takes no extra arguments", error); + goto out; + } + + booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + if (!booted_deployment) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Not currently booted into an OSTree system"); + goto out; + } + + target_state = opt_hotfix ? OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX : OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT; + + if (!ostree_sysroot_deployment_unlock (sysroot, booted_deployment, + target_state, cancellable, error)) + goto out; + + switch (target_state) + { + case OSTREE_DEPLOYMENT_UNLOCKED_NONE: + g_assert_not_reached (); + break; + case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX: + g_print ("Hotfix mode enabled. A writable overlayfs is now mounted on /usr\n" + "for this booted deployment. A non-hotfixed clone has been created\n" + "as the non-default rollback target.\n"); + break; + case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT: + g_print ("Development mode enabled. A writable overlayfs is now mounted on /usr.\n" + "All changes there will be discarded on reboot.\n"); + break; + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c new file mode 100644 index 0000000..eafe8bc --- /dev/null +++ b/src/ostree/ot-admin-builtin-upgrade.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2012 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "otutil.h" + +#include +#include +#include + +static gboolean opt_reboot; +static gboolean opt_allow_downgrade; +static gboolean opt_pull_only; +static gboolean opt_deploy_only; +static char *opt_osname; +static char *opt_override_commit; + +static GOptionEntry options[] = { + { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, + { "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Reboot after a successful upgrade", NULL }, + { "allow-downgrade", 0, 0, G_OPTION_ARG_NONE, &opt_allow_downgrade, "Permit deployment of chronologically older trees", NULL }, + { "override-commit", 0, 0, G_OPTION_ARG_STRING, &opt_override_commit, "Deploy CHECKSUM instead of the latest tree", "CHECKSUM" }, + { "pull-only", 0, 0, G_OPTION_ARG_NONE, &opt_pull_only, "Do not create a deployment, just download", NULL }, + { "deploy-only", 0, 0, G_OPTION_ARG_NONE, &opt_deploy_only, "Do not pull, only deploy", NULL }, + { NULL } +}; + +gboolean +ot_admin_builtin_upgrade (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new (""); + + g_autoptr(OstreeSysroot) sysroot = NULL; + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, + invocation, &sysroot, cancellable, error)) + return FALSE; + + if (opt_pull_only && opt_deploy_only) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot simultaneously specify --pull-only and --deploy-only"); + return FALSE; + } + else if (opt_pull_only && opt_reboot) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot simultaneously specify --pull-only and --reboot"); + return FALSE; + } + + g_autoptr(OstreeSysrootUpgrader) upgrader = + ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname, + cancellable, error); + if (!upgrader) + return FALSE; + + g_autoptr(GKeyFile) origin = ostree_sysroot_upgrader_dup_origin (upgrader); + if (origin != NULL) + { + /* Should we consider requiring --discard-hotfix here? */ + ostree_deployment_origin_remove_transient_state (origin); + if (opt_override_commit != NULL) + { + /* Override the commit to pull and deploy. */ + g_key_file_set_string (origin, "origin", + "override-commit", + opt_override_commit); + } + + if (!ostree_sysroot_upgrader_set_origin (upgrader, origin, NULL, error)) + return FALSE; + } + + gboolean changed; + OstreeSysrootUpgraderPullFlags upgraderpullflags = 0; + if (opt_deploy_only) + upgraderpullflags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC; + + { g_auto(GLnxConsoleRef) console = { 0, }; + glnx_console_lock (&console); + + g_autoptr(OstreeAsyncProgress) progress = NULL; + if (console.is_tty) + progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); + + if (opt_allow_downgrade) + upgraderpullflags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER; + + if (!ostree_sysroot_upgrader_pull (upgrader, 0, upgraderpullflags, + progress, &changed, + cancellable, error)) + { + /* In the pull-only case, we do a cleanup here to ensure that if + * multiple commits were pulled, we garbage collect any old + * partially-pulled intermediate commits before pulling more. This is + * really a best practice in general, but for maximum compatiblity, we + * only do cleanup if a user specifies the new --pull-only option. + * Otherwise, we would break the case of trying to deploy a commit that + * isn't directly referenced. + */ + if (opt_pull_only) + (void) ostree_sysroot_cleanup (sysroot, NULL, NULL); + return FALSE; + } + + if (progress) + ostree_async_progress_finish (progress); + } + + if (!changed) + { + g_print ("No update available.\n"); + } + else + { + if (!opt_pull_only) + { + if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error)) + return FALSE; + } + + if (opt_reboot) + { + if (!ot_admin_execve_reboot (sysroot, error)) + return FALSE; + } + } + + return TRUE; +} diff --git a/src/ostree/ot-admin-builtins.h b/src/ostree/ot-admin-builtins.h new file mode 100644 index 0000000..d88fc0b --- /dev/null +++ b/src/ostree/ot-admin-builtins.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define BUILTINPROTO(name) gboolean ot_admin_builtin_ ## name (int argc, char **argv, \ + OstreeCommandInvocation *invocation, \ + GCancellable *cancellable, GError **error) + +BUILTINPROTO(selinux_ensure_labeled); +BUILTINPROTO(os_init); +BUILTINPROTO(install); +BUILTINPROTO(instutil); +BUILTINPROTO(init_fs); +BUILTINPROTO(undeploy); +BUILTINPROTO(deploy); +BUILTINPROTO(cleanup); +BUILTINPROTO(pin); +BUILTINPROTO(finalize_staged); +BUILTINPROTO(unlock); +BUILTINPROTO(status); +BUILTINPROTO(set_origin); +BUILTINPROTO(diff); +BUILTINPROTO(switch); +BUILTINPROTO(upgrade); + +#undef BUILTINPROTO + +G_END_DECLS diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c new file mode 100644 index 0000000..d52836e --- /dev/null +++ b/src/ostree/ot-admin-functions.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2012 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "libglnx.h" +#include "ot-admin-functions.h" +#include "otutil.h" +#include "ostree.h" + +gboolean +ot_admin_require_booted_deployment_or_osname (OstreeSysroot *sysroot, + const char *osname, + GCancellable *cancellable, + GError **error) +{ + OstreeDeployment *booted_deployment = + ostree_sysroot_get_booted_deployment (sysroot); + if (booted_deployment == NULL && osname == NULL) + return glnx_throw (error, "Not currently booted into an OSTree system and no --os= argument given"); + return TRUE; +} + +/** + * ot_admin_checksum_version: + * @checksum: A GVariant from an ostree checksum. + * + * + * Get the version metadata string from a commit variant object, if it exists. + * + * Returns: A newly allocated string of the version, or %NULL is none + */ +char * +ot_admin_checksum_version (GVariant *checksum) +{ + g_autoptr(GVariant) metadata = NULL; + const char *ret = NULL; + + metadata = g_variant_get_child_value (checksum, 0); + + if (!g_variant_lookup (metadata, OSTREE_COMMIT_META_KEY_VERSION, "&s", &ret)) + return NULL; + + return g_strdup (ret); +} + +OstreeDeployment * +ot_admin_get_indexed_deployment (OstreeSysroot *sysroot, + int index, + GError **error) + +{ + g_autoptr(GPtrArray) current_deployments = + ostree_sysroot_get_deployments (sysroot); + + if (index < 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Invalid index %d", index); + return NULL; + } + if (index >= current_deployments->len) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "Out of range deployment index %d, expected < %d", index, + current_deployments->len); + return NULL; + } + + return g_object_ref (current_deployments->pdata[index]); +} + +struct ContextState { + GMainContext *mainctx; + gboolean running; +}; + +static gboolean +on_sysroot_lock_timeout (gpointer user_data) +{ + g_print ("Waiting for sysroot lock...\n"); + return TRUE; +} + +static void +on_sysroot_lock_acquired (OstreeSysroot *sysroot, + GAsyncResult *result, + struct ContextState *state) +{ + state->running = FALSE; + g_main_context_wakeup (state->mainctx); +} + +gboolean +ot_admin_sysroot_lock (OstreeSysroot *sysroot, + GError **error) +{ + gboolean ret = FALSE; + gboolean acquired; + struct ContextState state = { + .mainctx = g_main_context_new (), + .running = TRUE, + }; + + g_main_context_push_thread_default (state.mainctx); + + if (!ostree_sysroot_try_lock (sysroot, &acquired, error)) + goto out; + + if (!acquired) + { + GSource *timeout_src = g_timeout_source_new_seconds (3); + g_source_set_callback (timeout_src, (GSourceFunc)on_sysroot_lock_timeout, &state, NULL); + g_source_attach (timeout_src, state.mainctx); + g_source_unref (timeout_src); + + on_sysroot_lock_timeout (&state); + + ostree_sysroot_lock_async (sysroot, NULL, (GAsyncReadyCallback)on_sysroot_lock_acquired, &state); + + while (state.running) + g_main_context_iteration (state.mainctx, TRUE); + } + + ret = TRUE; + out: + g_main_context_pop_thread_default (state.mainctx); + g_main_context_unref (state.mainctx); + return ret; +} + +gboolean +ot_admin_execve_reboot (OstreeSysroot *sysroot, GError **error) +{ + OstreeDeployment *booted = ostree_sysroot_get_booted_deployment (sysroot); + + /* If the sysroot isn't booted, we shouldn't reboot, even if somehow the user + * asked for it; might accidentally be specified in a build script, etc. + */ + if (!booted) + return TRUE; + + if (execlp ("systemctl", "systemctl", "reboot", NULL) < 0) + return glnx_throw_errno_prefix (error, "execve(systemctl reboot)"); + return TRUE; +} diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h new file mode 100644 index 0000000..21e55ae --- /dev/null +++ b/src/ostree/ot-admin-functions.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +gboolean +ot_admin_require_booted_deployment_or_osname (OstreeSysroot *sysroot, + const char *osname, + GCancellable *cancellable, + GError **error); + +char * +ot_admin_checksum_version (GVariant *checksum); + +OstreeDeployment * +ot_admin_get_indexed_deployment (OstreeSysroot *sysroot, + int index, + GError **error); + +gboolean +ot_admin_sysroot_lock (OstreeSysroot *sysroot, + GError **error); + +gboolean +ot_admin_execve_reboot (OstreeSysroot *sysroot, + GError **error); + +G_END_DECLS diff --git a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c new file mode 100644 index 0000000..3ab5c24 --- /dev/null +++ b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include "ot-main.h" +#include "ot-admin-instutil-builtins.h" +#include "ostree-cmdprivate.h" + +#include "otutil.h" + +static GOptionEntry options[] = { + { NULL } +}; + +gboolean +ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + guint bootversion; + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + + context = g_option_context_new ("[BOOTVERSION]"); + + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + invocation, &sysroot, cancellable, error)) + goto out; + + if (argc >= 2) + { + bootversion = (guint) g_ascii_strtoull (argv[1], NULL, 10); + if (!(bootversion == 0 || bootversion == 1)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid bootversion: %u", bootversion); + goto out; + } + } + else + { + const char *bootversion_env = g_getenv ("_OSTREE_GRUB2_BOOTVERSION"); + if (bootversion_env) + bootversion = g_ascii_strtoull (bootversion_env, NULL, 10); + else + bootversion = ostree_sysroot_get_bootversion (sysroot); + g_assert (bootversion == 0 || bootversion == 1); + } + + if (!ostree_cmd__private__()->ostree_generate_grub2_config (sysroot, bootversion, 1, cancellable, error)) + goto out; + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c new file mode 100644 index 0000000..8bf75b3 --- /dev/null +++ b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include "ot-main.h" +#include "ot-admin-instutil-builtins.h" + +#include "otutil.h" + +static char * +ptrarray_path_join (GPtrArray *path) +{ + GString *path_buf; + + path_buf = g_string_new (""); + + if (path->len == 0) + g_string_append_c (path_buf, '/'); + else + { + guint i; + for (i = 0; i < path->len; i++) + { + const char *elt = path->pdata[i]; + + g_string_append_c (path_buf, '/'); + g_string_append (path_buf, elt); + } + } + + return g_string_free (path_buf, FALSE); +} + +static gboolean +relabel_one_path (OstreeSePolicy *sepolicy, + GFile *path, + GFileInfo *info, + GPtrArray *path_parts, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autofree char *relpath = NULL; + g_autofree char *new_label = NULL; + + relpath = ptrarray_path_join (path_parts); + if (!ostree_sepolicy_restorecon (sepolicy, relpath, + info, path, + OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL | + OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING, + &new_label, + cancellable, error)) + { + g_prefix_error (error, "Setting context of %s: ", gs_file_get_path_cached (path)); + goto out; + } + + if (new_label) + g_print ("Set label of '%s' (as '%s') to '%s'\n", + gs_file_get_path_cached (path), + relpath, + new_label); + + ret = TRUE; + out: + return ret; +} + +static gboolean +relabel_recursively (OstreeSePolicy *sepolicy, + GFile *dir, + GFileInfo *dir_info, + GPtrArray *path_parts, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GFileEnumerator) direnum = NULL; + + if (!relabel_one_path (sepolicy, dir, dir_info, path_parts, + cancellable, error)) + goto out; + + direnum = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!direnum) + goto out; + + while (TRUE) + { + GFileInfo *file_info; + GFile *child; + GFileType ftype; + + if (!g_file_enumerator_iterate (direnum, &file_info, &child, + cancellable, error)) + goto out; + if (file_info == NULL) + break; + + g_ptr_array_add (path_parts, (char*)g_file_info_get_name (file_info)); + + ftype = g_file_info_get_file_type (file_info); + if (ftype == G_FILE_TYPE_DIRECTORY) + { + if (!relabel_recursively (sepolicy, child, file_info, path_parts, + cancellable, error)) + goto out; + } + else + { + if (!relabel_one_path (sepolicy, child, file_info, path_parts, + cancellable, error)) + goto out; + } + + g_ptr_array_remove_index (path_parts, path_parts->len - 1); + } + + ret = TRUE; + out: + return ret; +} + +static gboolean +selinux_relabel_dir (OstreeSePolicy *sepolicy, + GFile *dir, + const char *prefix, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GPtrArray) path_parts = g_ptr_array_new (); + g_autoptr(GFileInfo) root_info = NULL; + + root_info = g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!root_info) + goto out; + + g_ptr_array_add (path_parts, (char*)prefix); + if (!relabel_recursively (sepolicy, dir, root_info, path_parts, + cancellable, error)) + { + g_prefix_error (error, "Relabeling /%s: ", prefix); + goto out; + } + + ret = TRUE; + out: + return ret; +} + +static GOptionEntry options[] = { + { NULL } +}; + +gboolean +ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + const char *policy_name; + g_autoptr(GFile) subpath = NULL; + const char *prefix = NULL; + g_autoptr(OstreeSePolicy) sepolicy = NULL; + g_autoptr(GPtrArray) deployments = NULL; + OstreeDeployment *first_deployment; + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + g_autoptr(GFile) deployment_path = NULL; + + context = g_option_context_new ("[SUBPATH PREFIX]"); + + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + invocation, &sysroot, cancellable, error)) + goto out; + + deployments = ostree_sysroot_get_deployments (sysroot); + if (deployments->len == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unable to find a deployment in sysroot"); + goto out; + } + first_deployment = deployments->pdata[0]; + deployment_path = ostree_sysroot_get_deployment_directory (sysroot, first_deployment); + + if (argc >= 2) + { + subpath = g_file_new_for_path (argv[1]); + prefix = argv[2]; + } + else + { + subpath = g_object_ref (deployment_path); + prefix = ""; + } + + sepolicy = ostree_sepolicy_new (deployment_path, cancellable, error); + if (!sepolicy) + goto out; + + policy_name = ostree_sepolicy_get_name (sepolicy); + if (policy_name) + { + g_print ("Relabeling using policy '%s'\n", policy_name); + if (!selinux_relabel_dir (sepolicy, subpath, prefix, + cancellable, error)) + goto out; + } + else + g_print ("No SELinux policy found in deployment '%s'\n", + gs_file_get_path_cached (deployment_path)); + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-admin-instutil-builtin-set-kargs.c b/src/ostree/ot-admin-instutil-builtin-set-kargs.c new file mode 100644 index 0000000..fb5c7d2 --- /dev/null +++ b/src/ostree/ot-admin-instutil-builtin-set-kargs.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * 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 of the licence 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., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include "ot-main.h" +#include "ot-admin-instutil-builtins.h" + +#include "otutil.h" +#include "ostree.h" + +static gboolean opt_proc_cmdline; +static gboolean opt_merge; +static char **opt_replace; +static char **opt_append; + +static GOptionEntry options[] = { + { "import-proc-cmdline", 0, 0, G_OPTION_ARG_NONE, &opt_proc_cmdline, "Import current /proc/cmdline", NULL }, + { "merge", 0, 0, G_OPTION_ARG_NONE, &opt_merge, "Merge with previous command line", NULL }, + { "replace", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_replace, "Set kernel argument, like root=/dev/sda1; this overrides any earlier argument with the same name", "NAME=VALUE" }, + { "append", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_append, "Append kernel argument; useful with e.g. console= that can be used multiple times", "NAME=VALUE" }, + { NULL } +}; + +gboolean +ot_admin_instutil_builtin_set_kargs (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + guint i; + g_autoptr(GPtrArray) deployments = NULL; + OstreeDeployment *first_deployment = NULL; + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + g_autoptr(OstreeKernelArgs) kargs = NULL; + + context = g_option_context_new ("ARGS"); + + if (!ostree_admin_option_context_parse (context, options, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + invocation, &sysroot, cancellable, error)) + goto out; + + deployments = ostree_sysroot_get_deployments (sysroot); + if (deployments->len == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unable to find a deployment in sysroot"); + goto out; + } + first_deployment = deployments->pdata[0]; + + kargs = ostree_kernel_args_new (); + + /* If they want the current kernel's args, they very likely don't + * want the ones from the merge. + */ + if (opt_proc_cmdline) + { + if (!ostree_kernel_args_append_proc_cmdline (kargs, cancellable, error)) + goto out; + } + else if (opt_merge) + { + OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (first_deployment); + g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1); + + ostree_kernel_args_append_argv (kargs, previous_args); + } + + if (opt_replace) + { + ostree_kernel_args_replace_argv (kargs, opt_replace); + } + + if (opt_append) + { + ostree_kernel_args_append_argv (kargs, opt_append); + } + + for (i = 1; i < argc; i++) + ostree_kernel_args_append (kargs, argv[i]); + + { + g_auto(GStrv) kargs_strv = ostree_kernel_args_to_strv (kargs); + + if (!ostree_sysroot_deployment_set_kargs (sysroot, first_deployment, + kargs_strv, + cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-admin-instutil-builtins.h b/src/ostree/ot-admin-instutil-builtins.h new file mode 100644 index 0000000..b0ab9e4 --- /dev/null +++ b/src/ostree/ot-admin-instutil-builtins.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error); +gboolean ot_admin_instutil_builtin_set_kargs (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error); +gboolean ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error); + +G_END_DECLS diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c new file mode 100644 index 0000000..9f1a615 --- /dev/null +++ b/src/ostree/ot-builtin-admin.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ot-admin-builtins.h" +#include "ot-admin-functions.h" +#include "ostree.h" +#include "ostree-repo-file.h" + +#include + +static OstreeCommand admin_subcommands[] = { + { "cleanup", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_cleanup, + "Delete untagged deployments and repository objects" }, + { "config-diff", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_diff, + "Diff current /etc configuration versus default" }, + { "deploy", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_deploy, + "Checkout revision REFSPEC as the new default deployment" }, + { "finalize-staged", OSTREE_BUILTIN_FLAG_NO_REPO | OSTREE_BUILTIN_FLAG_HIDDEN, + ot_admin_builtin_finalize_staged, + "Internal command to run at shutdown time" }, + { "init-fs", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_init_fs, + "Initialize a root filesystem" }, + { "instutil", OSTREE_BUILTIN_FLAG_NO_REPO | OSTREE_BUILTIN_FLAG_HIDDEN, + ot_admin_builtin_instutil, + "Deprecated commands intended for installer programs" }, + { "os-init", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_os_init, + "Initialize empty state for given operating system" }, + { "pin", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_pin, + "Change the \"pinning\" state of a deployment" }, + { "set-origin", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_set_origin, + "Set Origin and create a new origin file" }, + { "status", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_status, + "List deployments" }, + { "switch", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_switch, + "Construct new tree from REF and deploy it" }, + { "undeploy", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_undeploy, + "Delete deployment INDEX" }, + { "unlock", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_unlock, + "Make the current deployment mutable (as a hotfix or development)" }, + { "upgrade", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_admin_builtin_upgrade, + "Construct new tree from current origin and deploy it, if it changed" }, + { NULL, 0, NULL, NULL } +}; + +static GOptionContext * +ostree_admin_option_context_new_with_commands (void) +{ + OstreeCommand *command = admin_subcommands; + GOptionContext *context = g_option_context_new ("--print-current-dir|COMMAND"); + + g_autoptr(GString) summary = g_string_new ("Builtin \"admin\" Commands:"); + + while (command->name != NULL) + { + if ((command->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0) + { + g_string_append_printf (summary, "\n %-19s", command->name); + if (command->description != NULL) + g_string_append_printf (summary, "%s", command->description); + } + command++; + } + + g_option_context_set_summary (context, summary->str); + + return context; +} + +gboolean +ostree_builtin_admin (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + const char *subcommand_name = NULL; + OstreeCommand *subcommand; + g_autofree char *prgname = NULL; + int in, out; + + /* + * Parse the global options. We rearrange the options as + * necessary, in order to pass relevant options through + * to the commands, but also have them take effect globally. + */ + + for (in = 1, out = 1; in < argc; in++, out++) + { + /* The non-option is the command, take it out of the arguments */ + if (argv[in][0] != '-') + { + if (subcommand_name == NULL) + { + subcommand_name = argv[in]; + out--; + continue; + } + } + + else if (g_str_equal (argv[in], "--")) + { + break; + } + + argv[out] = argv[in]; + } + + argc = out; + + subcommand = admin_subcommands; + while (subcommand->name) + { + if (g_strcmp0 (subcommand_name, subcommand->name) == 0) + break; + subcommand++; + } + + if (!subcommand->name) + { + g_autoptr(GOptionContext) context = NULL; + g_autofree char *help = NULL; + + context = ostree_admin_option_context_new_with_commands (); + + /* This will not return for some options (e.g. --version). */ + if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, + invocation, NULL, cancellable, error)) + { + if (subcommand_name == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No \"admin\" subcommand specified"); + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Unknown \"admin\" subcommand '%s'", subcommand_name); + } + } + + help = g_option_context_get_help (context, FALSE, NULL); + g_printerr ("%s", help); + + goto out; + } + + prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name); + g_set_prgname (prgname); + + OstreeCommandInvocation sub_invocation = { .command = subcommand }; + if (!subcommand->fn (argc, argv, &sub_invocation, cancellable, error)) + goto out; + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-builtin-cat.c b/src/ostree/ot-builtin-cat.c new file mode 100644 index 0000000..5325705 --- /dev/null +++ b/src/ostree/ot-builtin-cat.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +#include + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-cat.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { NULL }, +}; + +static gboolean +cat_one_file (GFile *f, + GOutputStream *stdout_stream, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GInputStream) in = (GInputStream*)g_file_read (f, cancellable, error); + if (!in) + return FALSE; + + if (g_output_stream_splice (stdout_stream, in, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE, + cancellable, error) < 0) + return FALSE; + + return TRUE; +} + +gboolean +ostree_builtin_cat (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new ("COMMIT PATH..."); + g_autoptr(OstreeRepo) repo = NULL; + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (argc <= 2) + { + ot_util_usage_error (context, "A COMMIT and at least one PATH argument are required", error); + return FALSE; + } + const char *rev = argv[1]; + + g_autoptr(GFile) root = NULL; + if (!ostree_repo_read_commit (repo, rev, &root, NULL, NULL, error)) + return FALSE; + + g_autoptr(GOutputStream) stdout_stream = g_unix_output_stream_new (1, FALSE); + + for (int i = 2; i < argc; i++) + { + g_autoptr(GFile) f = g_file_resolve_relative_path (root, argv[i]); + + if (!cat_one_file (f, stdout_stream, cancellable, error)) + return FALSE; + } + + return TRUE; +} diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c new file mode 100644 index 0000000..813dbb9 --- /dev/null +++ b/src/ostree/ot-builtin-checkout.c @@ -0,0 +1,407 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +static gboolean opt_user_mode; +static gboolean opt_allow_noent; +static gboolean opt_disable_cache; +static char *opt_subpath; +static gboolean opt_union; +static gboolean opt_union_add; +static gboolean opt_union_identical; +static gboolean opt_whiteouts; +static gboolean opt_from_stdin; +static char *opt_from_file; +static gboolean opt_disable_fsync; +static gboolean opt_require_hardlinks; +static gboolean opt_force_copy; +static gboolean opt_force_copy_zerosized; +static gboolean opt_bareuseronly_dirs; +static char *opt_skiplist_file; +static char *opt_selinux_policy; +static char *opt_selinux_prefix; + +static gboolean +parse_fsync_cb (const char *option_name, + const char *value, + gpointer data, + GError **error) +{ + gboolean val; + + if (!ot_parse_boolean (value, &val, error)) + return FALSE; + + opt_disable_fsync = !val; + + return TRUE; +} + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-checkout.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "user-mode", 'U', 0, G_OPTION_ARG_NONE, &opt_user_mode, "Do not change file ownership or initialize extended attributes", NULL }, + { "disable-cache", 0, 0, G_OPTION_ARG_NONE, &opt_disable_cache, "Do not update or use the internal repository uncompressed object cache", NULL }, + { "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, + { "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL }, + { "union-add", 0, 0, G_OPTION_ARG_NONE, &opt_union_add, "Keep existing files/directories, only add new", NULL }, + { "union-identical", 0, 0, G_OPTION_ARG_NONE, &opt_union_identical, "When layering checkouts, error out if a file would be replaced with a different version, but add new files and directories", NULL }, + { "whiteouts", 0, 0, G_OPTION_ARG_NONE, &opt_whiteouts, "Process 'whiteout' (Docker style) entries", NULL }, + { "allow-noent", 0, 0, G_OPTION_ARG_NONE, &opt_allow_noent, "Do nothing if specified path does not exist", NULL }, + { "from-stdin", 0, 0, G_OPTION_ARG_NONE, &opt_from_stdin, "Process many checkouts from standard input", NULL }, + { "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", "FILE" }, + { "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" }, + { "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL }, + { "force-copy-zerosized", 'z', 0, G_OPTION_ARG_NONE, &opt_force_copy_zerosized, "Do not hardlink zero-sized files", NULL }, + { "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL }, + { "bareuseronly-dirs", 'M', 0, G_OPTION_ARG_NONE, &opt_bareuseronly_dirs, "Suppress mode bits outside of 0775 for directories (suid, world writable, etc.)", NULL }, + { "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "FILE" }, + { "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /); implies --force-copy", "PATH" }, + { "selinux-prefix", 0, 0, G_OPTION_ARG_STRING, &opt_selinux_prefix, "When setting SELinux labels, prefix all paths by PREFIX", "PREFIX" }, + { NULL } +}; + +static gboolean +handle_skiplist_line (const char *line, + void *data, + GError **error) +{ + GHashTable *files = data; + g_hash_table_add (files, g_strdup (line)); + return TRUE; +} + +static OstreeRepoCheckoutFilterResult +checkout_filter (OstreeRepo *self, + const char *path, + struct stat *st_buf, + gpointer user_data) +{ + GHashTable *skiplist = user_data; + if (g_hash_table_contains (skiplist, path)) + return OSTREE_REPO_CHECKOUT_FILTER_SKIP; + return OSTREE_REPO_CHECKOUT_FILTER_ALLOW; +} + +static gboolean +process_one_checkout (OstreeRepo *repo, + const char *resolved_commit, + const char *subpath, + const char *destination, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + + /* This strange code structure is to preserve testing + * coverage of both `ostree_repo_checkout_tree` and + * `ostree_repo_checkout_at` until such time as we have a more + * convenient infrastructure for testing C APIs with data. + */ + if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || + opt_union_add || opt_force_copy || opt_force_copy_zerosized || + opt_bareuseronly_dirs || opt_union_identical || + opt_skiplist_file || opt_selinux_policy || opt_selinux_prefix) + { + OstreeRepoCheckoutAtOptions options = { 0, }; + + /* do this early so option checking also catches force copy conflicts */ + if (opt_selinux_policy) + opt_force_copy = TRUE; + + if (opt_user_mode) + options.mode = OSTREE_REPO_CHECKOUT_MODE_USER; + /* Can't union these */ + if (opt_union && opt_union_add) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot specify both --union and --union-add"); + goto out; + } + if (opt_union && opt_union_identical) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot specify both --union and --union-identical"); + goto out; + } + if (opt_union_add && opt_union_identical) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot specify both --union-add and --union-identical "); + goto out; + } + if (opt_require_hardlinks && opt_force_copy) + { + glnx_throw (error, "Cannot specify both --require-hardlinks and --force-copy"); + goto out; + } + if (opt_selinux_prefix && !opt_selinux_policy) + { + glnx_throw (error, "Cannot specify --selinux-prefix without --selinux-policy"); + goto out; + } + else if (opt_union) + options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; + else if (opt_union_add) + options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES; + else if (opt_union_identical) + { + if (!opt_require_hardlinks) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "--union-identical requires --require-hardlinks"); + goto out; + } + options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL; + } + if (opt_whiteouts) + options.process_whiteouts = TRUE; + if (subpath) + options.subpath = subpath; + + g_autoptr(OstreeSePolicy) policy = NULL; + if (opt_selinux_policy) + { + glnx_autofd int rootfs_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error)) + { + g_prefix_error (error, "selinux-policy: "); + goto out; + } + policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error); + if (!policy) + goto out; + options.sepolicy = policy; + options.sepolicy_prefix = opt_selinux_prefix; + } + + g_autoptr(GHashTable) skip_list = + g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + if (opt_skiplist_file) + { + if (!ot_parse_file_by_line (opt_skiplist_file, handle_skiplist_line, skip_list, + cancellable, error)) + goto out; + options.filter = checkout_filter; + options.filter_user_data = skip_list; + } + + options.no_copy_fallback = opt_require_hardlinks; + options.force_copy = opt_force_copy; + options.force_copy_zerosized = opt_force_copy_zerosized; + options.bareuseronly_dirs = opt_bareuseronly_dirs; + + if (!ostree_repo_checkout_at (repo, &options, + AT_FDCWD, destination, + resolved_commit, + cancellable, error)) + goto out; + } + else + { + GError *tmp_error = NULL; + g_autoptr(GFile) root = NULL; + g_autoptr(GFile) subtree = NULL; + g_autoptr(GFileInfo) file_info = NULL; + g_autoptr(GFile) destination_file = g_file_new_for_path (destination); + + if (!ostree_repo_read_commit (repo, resolved_commit, &root, NULL, cancellable, error)) + goto out; + + if (subpath) + subtree = g_file_resolve_relative_path (root, subpath); + else + subtree = g_object_ref (root); + + file_info = g_file_query_info (subtree, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, &tmp_error); + if (!file_info) + { + if (opt_allow_noent + && g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&tmp_error); + ret = TRUE; + } + else + { + g_propagate_error (error, tmp_error); + } + goto out; + } + + if (!ostree_repo_checkout_tree (repo, opt_user_mode ? OSTREE_REPO_CHECKOUT_MODE_USER : 0, + opt_union ? OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES : 0, + destination_file, + OSTREE_REPO_FILE (subtree), file_info, + cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} + +static gboolean +process_many_checkouts (OstreeRepo *repo, + const char *target, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + gsize len; + GError *temp_error = NULL; + g_autoptr(GInputStream) instream = NULL; + g_autoptr(GDataInputStream) datastream = NULL; + g_autofree char *revision = NULL; + g_autofree char *subpath = NULL; + g_autofree char *resolved_commit = NULL; + + if (opt_from_stdin) + { + instream = (GInputStream*)g_unix_input_stream_new (0, FALSE); + } + else + { + g_autoptr(GFile) f = g_file_new_for_path (opt_from_file); + + instream = (GInputStream*)g_file_read (f, cancellable, error); + if (!instream) + goto out; + } + + datastream = g_data_input_stream_new (instream); + + while ((revision = g_data_input_stream_read_upto (datastream, "", 1, &len, + cancellable, &temp_error)) != NULL) + { + if (revision[0] == '\0') + break; + + /* Read the null byte */ + (void) g_data_input_stream_read_byte (datastream, cancellable, NULL); + g_free (subpath); + subpath = g_data_input_stream_read_upto (datastream, "", 1, &len, + cancellable, &temp_error); + if (temp_error) + { + g_propagate_error (error, temp_error); + goto out; + } + + /* Read the null byte */ + (void) g_data_input_stream_read_byte (datastream, cancellable, NULL); + + if (!ostree_repo_resolve_rev (repo, revision, FALSE, &resolved_commit, error)) + goto out; + + if (!process_one_checkout (repo, resolved_commit, subpath, target, + cancellable, error)) + { + g_prefix_error (error, "Processing tree %s: ", resolved_commit); + goto out; + } + + g_free (revision); + } + if (temp_error) + { + g_propagate_error (error, temp_error); + goto out; + } + + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_builtin_checkout (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + gboolean ret = FALSE; + const char *commit; + const char *destination; + g_autofree char *resolved_commit = NULL; + + context = g_option_context_new ("COMMIT [DESTINATION]"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (opt_disable_fsync) + ostree_repo_set_disable_fsync (repo, TRUE); + + if (argc < 2) + { + gchar *help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s\n", help); + g_free (help); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "COMMIT must be specified"); + goto out; + } + + if (opt_from_stdin || opt_from_file) + { + destination = argv[1]; + + if (!process_many_checkouts (repo, destination, cancellable, error)) + goto out; + } + else + { + commit = argv[1]; + if (argc < 3) + destination = commit; + else + destination = argv[2]; + + if (!ostree_repo_resolve_rev (repo, commit, FALSE, &resolved_commit, error)) + goto out; + + if (!process_one_checkout (repo, resolved_commit, opt_subpath, + destination, + cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-builtin-checksum.c b/src/ostree/ot-builtin-checksum.c new file mode 100644 index 0000000..354fa2e --- /dev/null +++ b/src/ostree/ot-builtin-checksum.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" + +#include + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-checksum.xml) when changing the option list. + */ + +static gboolean opt_ignore_xattrs; + +static GOptionEntry options[] = { + { "ignore-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_ignore_xattrs, "Don't include xattrs in checksum", NULL }, + { NULL } +}; + +typedef struct { + GError **error; + gboolean success; + GMainLoop *loop; +} AsyncChecksumData; + +static void +on_checksum_received (GObject *obj, + GAsyncResult *result, + gpointer user_data) +{ + AsyncChecksumData *data = user_data; + + g_autofree guchar *csum_bytes = NULL; + data->success = + ostree_checksum_file_async_finish ((GFile*)obj, result, &csum_bytes, data->error); + if (data->success) + { + char csum[OSTREE_SHA256_STRING_LEN+1]; + ostree_checksum_inplace_from_bytes (csum_bytes, csum); + g_print ("%s\n", csum); + } + + g_main_loop_quit (data->loop); +} + +gboolean +ostree_builtin_checksum (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = + g_option_context_new ("PATH"); + if (!ostree_option_context_parse (context, options, &argc, &argv, + invocation, NULL, cancellable, error)) + return FALSE; + + if (argc < 2) + return glnx_throw (error, "A filename must be given"); + const char *path = argv[1]; + + /* for test coverage, use the async API if no flags are needed */ + if (!opt_ignore_xattrs) + { + g_autoptr(GFile) f = g_file_new_for_path (path); + g_autoptr(GMainLoop) loop = g_main_loop_new (NULL, FALSE); + + AsyncChecksumData data = { 0, }; + + data.loop = loop; + data.error = error; + ostree_checksum_file_async (f, OSTREE_OBJECT_TYPE_FILE, G_PRIORITY_DEFAULT, + cancellable, on_checksum_received, &data); + g_main_loop_run (data.loop); + return data.success; + } + + g_autofree char *checksum = NULL; + if (!ostree_checksum_file_at (AT_FDCWD, path, NULL, OSTREE_OBJECT_TYPE_FILE, + OSTREE_CHECKSUM_FLAGS_IGNORE_XATTRS, &checksum, + cancellable, error)) + return FALSE; + + g_print ("%s\n", checksum); + return TRUE; +} diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c new file mode 100644 index 0000000..20409fc --- /dev/null +++ b/src/ostree/ot-builtin-commit.c @@ -0,0 +1,961 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ot-editor.h" +#include "ostree.h" +#include "otutil.h" +#include "parse-datetime.h" +#include "ostree-repo-private.h" +#include "ostree-libarchive-private.h" +#include "ostree-sign.h" + +static char *opt_subject; +static char *opt_body; +static char *opt_body_file; +static gboolean opt_editor; +static char *opt_parent; +static gboolean opt_orphan; +static gboolean opt_no_bindings; +static char **opt_bind_refs; +static char *opt_branch; +static char *opt_statoverride_file; +static char *opt_skiplist_file; +static char **opt_metadata_strings; +static char **opt_metadata_variants; +static char **opt_detached_metadata_strings; +static char **opt_metadata_keep; +static gboolean opt_link_checkout_speedup; +static gboolean opt_skip_if_unchanged; +static gboolean opt_tar_autocreate_parents; +static char *opt_tar_pathname_filter; +static gboolean opt_no_xattrs; +static char *opt_selinux_policy; +static gboolean opt_selinux_policy_from_base; +static gboolean opt_canonical_permissions; +static gboolean opt_ro_executables; +static gboolean opt_consume; +static gboolean opt_devino_canonical; +static char *opt_base; +static char **opt_trees; +static gint opt_owner_uid = -1; +static gint opt_owner_gid = -1; +static gboolean opt_table_output; +#ifndef OSTREE_DISABLE_GPGME +static char **opt_gpg_key_ids; +static char *opt_gpg_homedir; +#endif +static char **opt_key_ids; +static char *opt_sign_name; +static gboolean opt_generate_sizes; +static gboolean opt_disable_fsync; +static char *opt_timestamp; + +static gboolean +parse_fsync_cb (const char *option_name, + const char *value, + gpointer data, + GError **error) +{ + gboolean val; + if (!ot_parse_boolean (value, &val, error)) + return FALSE; + + opt_disable_fsync = !val; + return TRUE; +} + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-commit.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "parent", 0, 0, G_OPTION_ARG_STRING, &opt_parent, "Parent ref, or \"none\"", "REF" }, + { "subject", 's', 0, G_OPTION_ARG_STRING, &opt_subject, "One line subject", "SUBJECT" }, + { "body", 'm', 0, G_OPTION_ARG_STRING, &opt_body, "Full description", "BODY" }, + { "body-file", 'F', 0, G_OPTION_ARG_FILENAME, &opt_body_file, "Commit message from FILE path", "FILE" }, + { "editor", 'e', 0, G_OPTION_ARG_NONE, &opt_editor, "Use an editor to write the commit message", NULL }, + { "branch", 'b', 0, G_OPTION_ARG_STRING, &opt_branch, "Branch", "BRANCH" }, + { "orphan", 0, 0, G_OPTION_ARG_NONE, &opt_orphan, "Create a commit without writing a ref", NULL }, + { "no-bindings", 0, 0, G_OPTION_ARG_NONE, &opt_no_bindings, "Do not write any ref bindings", NULL }, + { "bind-ref", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_bind_refs, "Add a ref to ref binding commit metadata", "BRANCH" }, + { "base", 0, 0, G_OPTION_ARG_STRING, &opt_base, "Start from the given commit as a base (no modifiers apply)", "REF" }, + { "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT" }, + { "add-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_strings, "Add a key/value pair to metadata", "KEY=VALUE" }, + { "add-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_variants, "Add a key/value pair to metadata, where the KEY is a string, an VALUE is g_variant_parse() formatted", "KEY=VALUE" }, + { "keep-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_keep, "Keep metadata KEY and its associated VALUE from parent", "KEY" }, + { "add-detached-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_detached_metadata_strings, "Add a key/value pair to detached metadata", "KEY=VALUE" }, + { "owner-uid", 0, 0, G_OPTION_ARG_INT, &opt_owner_uid, "Set file ownership user id", "UID" }, + { "owner-gid", 0, 0, G_OPTION_ARG_INT, &opt_owner_gid, "Set file ownership group id", "GID" }, + { "canonical-permissions", 0, 0, G_OPTION_ARG_NONE, &opt_canonical_permissions, "Canonicalize permissions in the same way bare-user does for hardlinked files", NULL }, + { "mode-ro-executables", 0, 0, G_OPTION_ARG_NONE, &opt_ro_executables, "Ensure executable files are not writable", NULL }, + { "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Do not import extended attributes", NULL }, + { "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /)", "PATH" }, + { "selinux-policy-from-base", 'P', 0, G_OPTION_ARG_NONE, &opt_selinux_policy_from_base, "Set SELinux labels based on first --tree argument", NULL }, + { "link-checkout-speedup", 0, 0, G_OPTION_ARG_NONE, &opt_link_checkout_speedup, "Optimize for commits of trees composed of hardlinks into the repository", NULL }, + { "devino-canonical", 'I', 0, G_OPTION_ARG_NONE, &opt_devino_canonical, "Assume hardlinked objects are unmodified. Implies --link-checkout-speedup", NULL }, + { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL }, + { "tar-pathname-filter", 0, 0, G_OPTION_ARG_STRING, &opt_tar_pathname_filter, "When loading tar archives, use REGEX,REPLACEMENT against path names", "REGEX,REPLACEMENT" }, + { "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &opt_skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL }, + { "statoverride", 0, 0, G_OPTION_ARG_FILENAME, &opt_statoverride_file, "File containing list of modifications to make to permissions", "PATH" }, + { "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" }, + { "consume", 0, 0, G_OPTION_ARG_NONE, &opt_consume, "Consume (delete) content after commit (for local directories)", NULL }, + { "table-output", 0, 0, G_OPTION_ARG_NONE, &opt_table_output, "Output more information in a KEY: VALUE format", NULL }, +#ifndef OSTREE_DISABLE_GPGME + { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_gpg_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"}, + { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, +#endif + { "sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "Sign the commit with", "KEY_ID"}, + { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"}, + { "generate-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_generate_sizes, "Generate size information along with commit metadata", NULL }, + { "disable-fsync", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, + { "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" }, + { "timestamp", 0, 0, G_OPTION_ARG_STRING, &opt_timestamp, "Override the timestamp of the commit", "TIMESTAMP" }, + { NULL } +}; + +struct CommitFilterData { + GHashTable *mode_adds; + GHashTable *mode_overrides; + GHashTable *skip_list; +}; + +static gboolean +handle_statoverride_line (const char *line, + void *data, + GError **error) +{ + struct CommitFilterData *cf = data; + const char *spc = strchr (line, ' '); + if (spc == NULL) + return glnx_throw (error, "Malformed statoverride file (no space found)"); + const char *fn = spc + 1; + + if (g_str_has_prefix (line, "=")) + { + guint mode_override = (guint32)(gint32)g_ascii_strtod (line+1, NULL); + g_hash_table_insert (cf->mode_overrides, g_strdup (fn), + GUINT_TO_POINTER((gint32)mode_override)); + } + else + { + guint mode_add = (guint32)(gint32)g_ascii_strtod (line, NULL); + g_hash_table_insert (cf->mode_adds, g_strdup (fn), + GUINT_TO_POINTER((gint32)mode_add)); + } + return TRUE; +} + +static gboolean +handle_skiplist_line (const char *line, + void *data, + GError **error) +{ + GHashTable *files = data; + g_hash_table_add (files, g_strdup (line)); + return TRUE; +} + +static OstreeRepoCommitFilterResult +commit_filter (OstreeRepo *self, + const char *path, + GFileInfo *file_info, + gpointer user_data) +{ + struct CommitFilterData *data = user_data; + GHashTable *mode_adds = data->mode_adds; + GHashTable *mode_overrides = data->mode_overrides; + GHashTable *skip_list = data->skip_list; + gpointer value; + + if (opt_owner_uid >= 0) + g_file_info_set_attribute_uint32 (file_info, "unix::uid", opt_owner_uid); + if (opt_owner_gid >= 0) + g_file_info_set_attribute_uint32 (file_info, "unix::gid", opt_owner_gid); + guint mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + + if (S_ISREG (mode) && opt_ro_executables && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + { + mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + g_file_info_set_attribute_uint32 (file_info, "unix::mode", mode); + } + + if (mode_adds && g_hash_table_lookup_extended (mode_adds, path, NULL, &value)) + { + guint mode_add = GPOINTER_TO_UINT (value); + g_file_info_set_attribute_uint32 (file_info, "unix::mode", + mode | mode_add); + g_hash_table_remove (mode_adds, path); + } + else if (mode_overrides && g_hash_table_lookup_extended (mode_overrides, path, NULL, &value)) + { + guint current_fmt = g_file_info_get_attribute_uint32 (file_info, "unix::mode") & S_IFMT; + guint mode_override = GPOINTER_TO_UINT (value); + g_file_info_set_attribute_uint32 (file_info, "unix::mode", + current_fmt | mode_override); + g_hash_table_remove (mode_adds, path); + } + + if (skip_list && g_hash_table_contains (skip_list, path)) + { + g_hash_table_remove (skip_list, path); + return OSTREE_REPO_COMMIT_FILTER_SKIP; + } + + return OSTREE_REPO_COMMIT_FILTER_ALLOW; +} + +#ifdef HAVE_LIBARCHIVE +typedef struct { + GRegex *regex; + const char *replacement; +} TranslatePathnameData; + +/* Implement --tar-pathname-filter */ +static char * +handle_translate_pathname (OstreeRepo *repo, + const struct stat *stbuf, + const char *path, + gpointer user_data) +{ + TranslatePathnameData *tpdata = user_data; + g_autoptr(GError) tmp_error = NULL; + char *ret = + g_regex_replace (tpdata->regex, path, -1, 0, + tpdata->replacement, 0, &tmp_error); + g_assert_no_error (tmp_error); + g_assert (ret); + return ret; +} +#endif + +static gboolean +commit_editor (OstreeRepo *repo, + const char *branch, + char **subject, + char **body, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *input = g_strdup_printf ("\n" + "# Please enter the commit message for your changes. The first line will\n" + "# become the subject, and the remainder the body. Lines starting\n" + "# with '#' will be ignored, and an empty message aborts the commit." + "%s%s%s%s%s%s\n" + , branch ? "\n#\n# Branch: " : "", branch ? branch : "" + , *subject ? "\n" : "", *subject ? *subject : "" + , *body ? "\n" : "", *body ? *body : "" + ); + + *subject = NULL; + *body = NULL; + + g_autofree char *output = ot_editor_prompt (repo, input, cancellable, error); + if (output == NULL) + return FALSE; + + g_auto(GStrv) lines = g_strsplit (output, "\n", -1); + g_autoptr(GString) bodybuf = NULL; + for (guint i = 0; lines[i] != NULL; i++) + { + g_strchomp (lines[i]); + + /* Lines starting with # are skipped */ + if (lines[i][0] == '#') + continue; + + /* Blank lines before body starts are skipped */ + if (lines[i][0] == '\0') + { + if (!bodybuf) + continue; + } + + if (!*subject) + { + *subject = g_strdup (lines[i]); + } + else if (!bodybuf) + { + bodybuf = g_string_new (lines[i]); + } + else + { + g_string_append_c (bodybuf, '\n'); + g_string_append (bodybuf, lines[i]); + } + } + + if (!*subject) + return glnx_throw (error, "Aborting commit due to empty commit subject."); + + if (bodybuf) + { + *body = g_string_free (g_steal_pointer (&bodybuf), FALSE); + g_strchomp (*body); + } + + return TRUE; +} + +static gboolean +parse_keyvalue_strings (GVariantBuilder *builder, + char **strings, + gboolean is_gvariant_print, + GError **error) +{ + for (char ** iter = strings; *iter; iter++) + { + const char *s = *iter; + const char *eq = strchr (s, '='); + if (!eq) + return glnx_throw (error, "Missing '=' in KEY=VALUE metadata '%s'", s); + g_autofree char *key = g_strndup (s, eq - s); + if (is_gvariant_print) + { + g_autoptr(GVariant) value = g_variant_parse (NULL, eq + 1, NULL, NULL, error); + if (!value) + return glnx_prefix_error (error, "Parsing %s", s); + + g_variant_builder_add (builder, "{sv}", key, value); + } + else + g_variant_builder_add (builder, "{sv}", key, + g_variant_new_string (eq + 1)); + } + + return TRUE; +} + +static void +add_collection_binding (OstreeRepo *repo, + GVariantBuilder *metadata_builder) +{ + const char *collection_id = ostree_repo_get_collection_id (repo); + + if (collection_id == NULL) + return; + + g_variant_builder_add (metadata_builder, "{s@v}", OSTREE_COMMIT_META_KEY_COLLECTION_BINDING, + g_variant_new_variant (g_variant_new_string (collection_id))); +} + +static int +compare_strings (gconstpointer a, gconstpointer b) +{ + const char **sa = (const char **)a; + const char **sb = (const char **)b; + + return strcmp (*sa, *sb); +} + +static void +add_ref_binding (GVariantBuilder *metadata_builder) +{ + g_assert (opt_branch != NULL || opt_orphan); + + g_autoptr(GPtrArray) refs = g_ptr_array_new (); + if (opt_branch != NULL) + g_ptr_array_add (refs, opt_branch); + for (char **iter = opt_bind_refs; iter != NULL && *iter != NULL; ++iter) + g_ptr_array_add (refs, *iter); + g_ptr_array_sort (refs, compare_strings); + g_autoptr(GVariant) refs_v = g_variant_new_strv ((const char *const *)refs->pdata, + refs->len); + g_variant_builder_add (metadata_builder, "{s@v}", OSTREE_COMMIT_META_KEY_REF_BINDING, + g_variant_new_variant (g_steal_pointer (&refs_v))); +} + +/* Note if you're using the API, you currently need to do this yourself */ +static void +fill_bindings (OstreeRepo *repo, + GVariant *metadata, + GVariant **out_metadata) +{ + g_autoptr(GVariantBuilder) metadata_builder = + ot_util_variant_builder_from_variant (metadata, G_VARIANT_TYPE_VARDICT); + + add_ref_binding (metadata_builder); + + /* Allow the collection ID to be overridden using + * --add-metadata-string=ostree.collection-binding=blah */ + if (metadata == NULL || + !g_variant_lookup (metadata, OSTREE_COMMIT_META_KEY_COLLECTION_BINDING, "*", NULL)) + add_collection_binding (repo, metadata_builder); + + *out_metadata = g_variant_ref_sink (g_variant_builder_end (metadata_builder)); +} + +gboolean +ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + gboolean ret = FALSE; + gboolean skip_commit = FALSE; + g_autoptr(GFile) object_to_commit = NULL; + g_autofree char *parent = NULL; + g_autofree char *commit_checksum = NULL; + g_autoptr(GFile) root = NULL; + g_autoptr(GVariant) metadata = NULL; + g_autoptr(GVariant) detached_metadata = NULL; + g_autoptr(OstreeMutableTree) mtree = NULL; + g_autofree char *tree_type = NULL; + g_autoptr(GHashTable) mode_adds = NULL; + g_autoptr(GHashTable) mode_overrides = NULL; + g_autoptr(GHashTable) skip_list = NULL; + OstreeRepoCommitModifierFlags flags = 0; + g_autoptr(OstreeSePolicy) policy = NULL; + OstreeRepoCommitModifier *modifier = NULL; + OstreeRepoTransactionStats stats; + struct CommitFilterData filter_data = { 0, }; + g_autofree char *commit_body = NULL; + g_autoptr (OstreeSign) sign = NULL; + + context = g_option_context_new ("[PATH]"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (!ostree_ensure_repo_writable (repo, error)) + goto out; + + if (opt_statoverride_file) + { + filter_data.mode_adds = mode_adds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + filter_data.mode_overrides = mode_overrides = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + if (!ot_parse_file_by_line (opt_statoverride_file, handle_statoverride_line, + &filter_data, cancellable, error)) + goto out; + } + + if (opt_skiplist_file) + { + skip_list = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + if (!ot_parse_file_by_line (opt_skiplist_file, handle_skiplist_line, + skip_list, cancellable, error)) + goto out; + } + + if (!(opt_branch || opt_orphan)) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "A branch must be specified with --branch, or use --orphan"); + goto out; + } + + if (opt_parent) + { + if (g_str_equal (opt_parent, "none")) + parent = NULL; + else + { + if (!ostree_validate_checksum_string (opt_parent, error)) + goto out; + parent = g_strdup (opt_parent); + } + } + else if (!opt_orphan) + { + if (!ostree_repo_resolve_rev (repo, opt_branch, TRUE, &parent, error)) + { + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) + { + /* A folder exists with the specified ref name, + * which is handled by _ostree_repo_write_ref */ + g_clear_error (error); + } + else goto out; + } + } + + if (!parent && opt_metadata_keep) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Either --branch or --parent must be specified when using " + "--keep-metadata"); + goto out; + } + + if (opt_metadata_strings || opt_metadata_variants || opt_metadata_keep) + { + g_autoptr(GVariantBuilder) builder = + g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + + if (opt_metadata_strings && + !parse_keyvalue_strings (builder, opt_metadata_strings, FALSE, error)) + goto out; + + if (opt_metadata_variants && + !parse_keyvalue_strings (builder, opt_metadata_variants, TRUE, error)) + goto out; + + if (opt_metadata_keep) + { + g_assert (parent); + + g_autoptr(GVariant) parent_commit = NULL; + if (!ostree_repo_load_commit (repo, parent, &parent_commit, NULL, error)) + goto out; + + g_auto(GVariantDict) dict; + g_variant_dict_init (&dict, g_variant_get_child_value (parent_commit, 0)); + for (char **keyp = opt_metadata_keep; keyp && *keyp; keyp++) + { + const char *key = *keyp; + g_autoptr(GVariant) val = g_variant_dict_lookup_value (&dict, key, NULL); + if (!val) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing metadata key '%s' from commit '%s'", key, parent); + goto out; + } + + g_variant_builder_add (builder, "{sv}", key, val); + } + } + + metadata = g_variant_ref_sink (g_variant_builder_end (builder)); + } + + if (opt_detached_metadata_strings) + { + g_autoptr(GVariantBuilder) builder = + g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + + if (!parse_keyvalue_strings (builder, opt_detached_metadata_strings, FALSE, error)) + goto out; + + detached_metadata = g_variant_ref_sink (g_variant_builder_end (builder)); + } + + if (opt_no_xattrs) + flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS; + if (opt_consume) + flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CONSUME; + if (opt_devino_canonical) + { + opt_link_checkout_speedup = TRUE; /* Imply this */ + flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_DEVINO_CANONICAL; + } + if (opt_canonical_permissions) + flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS; + if (opt_generate_sizes) + flags |= OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES; + if (opt_disable_fsync) + ostree_repo_set_disable_fsync (repo, TRUE); + if (opt_selinux_policy && opt_selinux_policy_from_base) + { + glnx_throw (error, "Cannot specify both --selinux-policy and --selinux-policy-from-base"); + goto out; + } + + if (flags != 0 + || opt_owner_uid >= 0 + || opt_owner_gid >= 0 + || opt_statoverride_file != NULL + || opt_skiplist_file != NULL + || opt_no_xattrs + || opt_ro_executables + || opt_selinux_policy + || opt_selinux_policy_from_base) + { + filter_data.mode_adds = mode_adds; + filter_data.skip_list = skip_list; + modifier = ostree_repo_commit_modifier_new (flags, commit_filter, + &filter_data, NULL); + } + + if (opt_editor) + { + if (!commit_editor (repo, opt_branch, &opt_subject, &commit_body, cancellable, error)) + goto out; + } + else if (opt_body_file) + { + commit_body = glnx_file_get_contents_utf8_at (AT_FDCWD, opt_body_file, NULL, + cancellable, error); + if (!commit_body) + goto out; + } + else if (opt_body) + commit_body = g_strdup (opt_body); + + if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) + goto out; + + if (opt_link_checkout_speedup && !ostree_repo_scan_hardlinks (repo, cancellable, error)) + goto out; + + if (opt_base) + { + g_autofree char *base_commit = NULL; + g_autoptr(GFile) root = NULL; + if (!ostree_repo_read_commit (repo, opt_base, &root, &base_commit, cancellable, error)) + goto out; + OstreeRepoFile *rootf = (OstreeRepoFile*) root; + + mtree = ostree_mutable_tree_new_from_checksum (repo, + ostree_repo_file_tree_get_contents_checksum (rootf), + ostree_repo_file_tree_get_metadata_checksum (rootf)); + + if (opt_selinux_policy_from_base) + { + g_assert (modifier); + if (!ostree_repo_commit_modifier_set_sepolicy_from_commit (modifier, repo, base_commit, cancellable, error)) + goto out; + /* Don't try to handle it twice */ + opt_selinux_policy_from_base = FALSE; + } + } + else + { + mtree = ostree_mutable_tree_new (); + } + + + /* Convert implicit . or explicit path via argv into + * --tree=dir= so that we only have one primary code path below. + */ + if (opt_trees == NULL || opt_trees[0] == NULL) + { + char *path; + if (argc <= 1) + path = "."; + else + path = argv[1]; + opt_trees = g_new0 (char *, 2); + opt_trees[0] = g_strconcat ("dir=", path, NULL); + } + + const char *const*tree_iter; + const char *tree; + const char *eq; + g_assert (opt_trees && *opt_trees); + for (tree_iter = (const char *const*)opt_trees; *tree_iter; tree_iter++) + { + const gboolean first = (tree_iter == (const char *const*)opt_trees); + tree = *tree_iter; + + eq = strchr (tree, '='); + if (!eq) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing type in tree specification '%s'", tree); + goto out; + } + g_free (tree_type); + tree_type = g_strndup (tree, eq - tree); + tree = eq + 1; + + g_clear_object (&object_to_commit); + if (strcmp (tree_type, "dir") == 0) + { + if (first && opt_selinux_policy_from_base) + { + opt_selinux_policy = g_strdup (tree); + opt_selinux_policy_from_base = FALSE; + } + if (first && opt_selinux_policy) + { + g_assert (modifier); + glnx_autofd int rootfs_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error)) + goto out; + policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error); + if (!policy) + goto out; + ostree_repo_commit_modifier_set_sepolicy (modifier, policy); + } + if (!ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, tree, mtree, modifier, + cancellable, error)) + goto out; + } + else if (strcmp (tree_type, "tar") == 0) + { + if (first && opt_selinux_policy_from_base) + { + glnx_throw (error, "Cannot use --selinux-policy-from-base with tar"); + goto out; + } + if (!opt_tar_pathname_filter) + { + if (strcmp (tree, "-") == 0) + { + if (!ostree_repo_write_archive_to_mtree_from_fd (repo, STDIN_FILENO, mtree, modifier, + opt_tar_autocreate_parents, + cancellable, error)) + goto out; + } + else + { + object_to_commit = g_file_new_for_path (tree); + + if (!ostree_repo_write_archive_to_mtree (repo, object_to_commit, mtree, modifier, + opt_tar_autocreate_parents, + cancellable, error)) + goto out; + } + } + else + { +#ifdef HAVE_LIBARCHIVE + const char *comma = strchr (opt_tar_pathname_filter, ','); + if (!comma) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing ',' in --tar-pathname-filter"); + goto out; + } + const char *replacement = comma + 1; + g_autofree char *regexp_text = g_strndup (opt_tar_pathname_filter, comma - opt_tar_pathname_filter); + /* Use new API if we have a pathname filter */ + OstreeRepoImportArchiveOptions opts = { 0, }; + opts.autocreate_parents = opt_tar_autocreate_parents; + opts.translate_pathname = handle_translate_pathname; + g_autoptr(GRegex) regexp = g_regex_new (regexp_text, 0, 0, error); + TranslatePathnameData tpdata = { regexp, replacement }; + if (!regexp) + { + g_prefix_error (error, "--tar-pathname-filter: "); + goto out; + } + opts.translate_pathname_user_data = &tpdata; + + g_autoptr(OtAutoArchiveRead) archive; + if (strcmp (tree, "-") == 0) + archive = ot_open_archive_read_fd (STDIN_FILENO, error); + else + archive = ot_open_archive_read (tree, error); + + if (!archive) + goto out; + if (!ostree_repo_import_archive_to_mtree (repo, &opts, archive, mtree, + modifier, cancellable, error)) + goto out; +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree is not compiled with libarchive support"); + goto out; +#endif + } + } + else if (strcmp (tree_type, "ref") == 0) + { + if (first && opt_selinux_policy_from_base) + { + g_assert (modifier); + if (!ostree_repo_commit_modifier_set_sepolicy_from_commit (modifier, repo, tree, cancellable, error)) + goto out; + } + if (!ostree_repo_read_commit (repo, tree, &object_to_commit, NULL, cancellable, error)) + goto out; + + if (!ostree_repo_write_directory_to_mtree (repo, object_to_commit, mtree, modifier, + cancellable, error)) + goto out; + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid tree type specification '%s'", tree_type); + goto out; + } + } + + if (mode_adds && g_hash_table_size (mode_adds) > 0) + { + GHashTableIter hash_iter; + gpointer key, value; + + g_hash_table_iter_init (&hash_iter, mode_adds); + + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + g_printerr ("Unmatched statoverride path: %s\n", (char*)key); + } + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unmatched statoverride paths"); + goto out; + } + + if (skip_list && g_hash_table_size (skip_list) > 0) + { + GHashTableIter hash_iter; + gpointer key; + + g_hash_table_iter_init (&hash_iter, skip_list); + + while (g_hash_table_iter_next (&hash_iter, &key, NULL)) + { + g_printerr ("Unmatched skip-list path: %s\n", (char*)key); + } + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unmatched skip-list paths"); + goto out; + } + + if (!ostree_repo_write_mtree (repo, mtree, &root, cancellable, error)) + goto out; + + if (opt_skip_if_unchanged && parent) + { + g_autoptr(GFile) parent_root; + + if (!ostree_repo_read_commit (repo, parent, &parent_root, NULL, cancellable, error)) + goto out; + + if (g_file_equal (root, parent_root)) + skip_commit = TRUE; + } + + if (!skip_commit) + { + if (!opt_no_bindings) + { + g_autoptr(GVariant) old_metadata = g_steal_pointer (&metadata); + fill_bindings (repo, old_metadata, &metadata); + } + + if (!opt_timestamp) + { + if (!ostree_repo_write_commit (repo, parent, opt_subject, commit_body, metadata, + OSTREE_REPO_FILE (root), + &commit_checksum, cancellable, error)) + goto out; + } + else + { + struct timespec ts; + if (!parse_datetime (&ts, opt_timestamp, NULL)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Could not parse '%s'", opt_timestamp); + goto out; + } + + guint64 timestamp = ts.tv_sec; + if (!ostree_repo_write_commit_with_time (repo, parent, opt_subject, commit_body, metadata, + OSTREE_REPO_FILE (root), + timestamp, + &commit_checksum, cancellable, error)) + goto out; + } + + if (detached_metadata) + { + if (!ostree_repo_write_commit_detached_metadata (repo, commit_checksum, + detached_metadata, + cancellable, error)) + goto out; + } + + if (opt_key_ids) + { + /* Initialize crypto system */ + opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519; + + sign = ostree_sign_get_by_name (opt_sign_name, error); + if (sign == NULL) + goto out; + + char **iter; + + for (iter = opt_key_ids; iter && *iter; iter++) + { + const char *keyid = *iter; + g_autoptr (GVariant) secret_key = NULL; + + secret_key = g_variant_new_string (keyid); + if (!ostree_sign_set_sk (sign, secret_key, error)) + goto out; + + if (!ostree_sign_commit (sign, + repo, + commit_checksum, + cancellable, + error)) + goto out; + } + } + +#ifndef OSTREE_DISABLE_GPGME + if (opt_gpg_key_ids) + { + char **iter; + + for (iter = opt_gpg_key_ids; iter && *iter; iter++) + { + const char *keyid = *iter; + + if (!ostree_repo_sign_commit (repo, + commit_checksum, + keyid, + opt_gpg_homedir, + cancellable, + error)) + goto out; + } + } +#endif + + if (opt_branch) + ostree_repo_transaction_set_ref (repo, NULL, opt_branch, commit_checksum); + else + g_assert (opt_orphan); + + if (!ostree_repo_commit_transaction (repo, &stats, cancellable, error)) + goto out; + } + else + { + commit_checksum = g_strdup (parent); + } + + if (opt_table_output) + { + g_print ("Commit: %s\n", commit_checksum); + g_print ("Metadata Total: %u\n", stats.metadata_objects_total); + g_print ("Metadata Written: %u\n", stats.metadata_objects_written); + g_print ("Content Total: %u\n", stats.content_objects_total); + g_print ("Content Written: %u\n", stats.content_objects_written); + g_print ("Content Cache Hits: %u\n", stats.devino_cache_hits); + g_print ("Content Bytes Written: %" G_GUINT64_FORMAT "\n", stats.content_bytes_written); + } + else + { + g_print ("%s\n", commit_checksum); + } + + ret = TRUE; + out: + if (repo) + ostree_repo_abort_transaction (repo, cancellable, NULL); + if (modifier) + ostree_repo_commit_modifier_unref (modifier); + return ret; +} diff --git a/src/ostree/ot-builtin-config.c b/src/ostree/ot-builtin-config.c new file mode 100644 index 0000000..811a838 --- /dev/null +++ b/src/ostree/ot-builtin-config.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +static char* opt_group; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-config.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "group", 0, 0, G_OPTION_ARG_STRING, &opt_group , "Group name", NULL }, + { NULL } +}; + +static gboolean +split_key_string (const char *k, + char **out_section, + char **out_value, + GError **error) +{ + const char *dot = strchr (k, '.'); + + if (!dot) + { + return glnx_throw (error, + "Key must be of the form \"sectionname.keyname\""); + } + + *out_section = g_strndup (k, dot - k); + *out_value = g_strdup (dot + 1); + + return TRUE; +} + +gboolean +ostree_builtin_config (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + const char *op; + const char *section_key; + const char *value; + g_autofree char *section = NULL; + g_autofree char *key = NULL; + g_autoptr(GKeyFile) config = NULL; + int correct_argc; + + context = g_option_context_new ("(get KEY|set KEY VALUE|unset KEY)"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (argc < 2) + { + ot_util_usage_error (context, "OPERATION must be specified", error); + return FALSE; + } + + op = argv[1]; + + if (!strcmp (op, "set")) + correct_argc = 4; + else + correct_argc = 3; + + if (argc > correct_argc) + { + ot_util_usage_error (context, "Too many arguments given", error); + return FALSE; + } + + if (!strcmp (op, "set")) + { + if (opt_group) + { + if (argc < 4) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "GROUP name, KEY and VALUE must be specified"); + return FALSE; + } + section = g_strdup(opt_group); + key = g_strdup(argv[2]); + value = argv[3]; + } + else + { + if (argc < 4) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "KEY and VALUE must be specified"); + return FALSE; + } + section_key = argv[2]; + value = argv[3]; + if(!split_key_string (section_key, §ion, &key, error)) + return FALSE; + } + + config = ostree_repo_copy_config (repo); + g_key_file_set_string (config, section, key, value); + + if (!ostree_repo_write_config (repo, config, error)) + return FALSE; + } + else if (!strcmp (op, "get")) + { + GKeyFile *readonly_config = NULL; + g_autofree char *value = NULL; + if (opt_group) + { + if (argc < 3) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Group name and key must be specified"); + return FALSE; + } + section = g_strdup(opt_group); + key = g_strdup(argv[2]); + } + else + { + if(argc < 3) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "KEY must be specified"); + return FALSE; + } + section_key = argv[2]; + if (!split_key_string (section_key, §ion, &key, error)) + return FALSE; + } + + readonly_config = ostree_repo_get_config (repo); + value = g_key_file_get_string (readonly_config, section, key, error); + if (value == NULL) + return FALSE; + + g_print ("%s\n", value); + } + else if (!strcmp (op, "unset")) + { + g_autoptr(GError) local_error = NULL; + if (opt_group) + { + if (argc < 3) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Group name and key must be specified"); + return FALSE; + } + section = g_strdup(opt_group); + key = g_strdup(argv[2]); + } + else + { + if (argc < 3) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "KEY must be specified"); + return FALSE; + } + section_key = argv[2]; + if (!split_key_string (section_key, §ion, &key, error)) + return FALSE; + } + + config = ostree_repo_copy_config (repo); + if (!g_key_file_remove_key (config, section, key, &local_error)) + { + if (!g_error_matches (local_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND) && + !g_error_matches (local_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + + if (local_error == NULL && !ostree_repo_write_config (repo, config, error)) + return FALSE; + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown operation %s", op); + return FALSE; + } + + return TRUE; +} diff --git a/src/ostree/ot-builtin-create-usb.c b/src/ostree/ot-builtin-create-usb.c new file mode 100644 index 0000000..849684f --- /dev/null +++ b/src/ostree/ot-builtin-create-usb.c @@ -0,0 +1,278 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +#include "ostree-remote-private.h" + +static gboolean opt_disable_fsync = FALSE; +static char *opt_destination_repo = NULL; +static char *opt_commit = NULL; + +static GOptionEntry options[] = + { + { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, + { "destination-repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_destination_repo, "Use custom repository directory within the mount", "DEST" }, + { "commit", 0, 0, G_OPTION_ARG_STRING, &opt_commit, "Pull a specific commit (only works when a single ref is specified)", "COMMIT" }, + { NULL } + }; + +gboolean +ostree_builtin_create_usb (int argc, + char **argv, + OstreeCommandInvocation *invocation, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeAsyncProgress) progress = NULL; + g_auto(GLnxConsoleRef) console = { 0, }; + + context = g_option_context_new ("MOUNT-PATH COLLECTION-ID REF [COLLECTION-ID REF...]"); + + /* Parse options. */ + g_autoptr(OstreeRepo) src_repo = NULL; + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &src_repo, cancellable, error)) + return FALSE; + + if (argc < 2) + { + ot_util_usage_error (context, "A MOUNT-PATH must be specified", error); + return FALSE; + } + + if (argc < 4) + { + ot_util_usage_error (context, "At least one COLLECTION-ID REF pair must be specified", error); + return FALSE; + } + + if (argc % 2 == 1) + { + ot_util_usage_error (context, "Only complete COLLECTION-ID REF pairs may be specified", error); + return FALSE; + } + + if (opt_commit && argc > 4) + { + ot_util_usage_error (context, "The --commit option can only be used when a single COLLECTION-ID REF pair is specified", error); + return FALSE; + } + + /* Open the USB stick, which must exist. Allow automounting and following symlinks. */ + const char *mount_root_path = argv[1]; + struct stat mount_root_stbuf; + + glnx_autofd int mount_root_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, mount_root_path, TRUE, &mount_root_dfd, error)) + return FALSE; + if (!glnx_fstat (mount_root_dfd, &mount_root_stbuf, error)) + return FALSE; + + /* Read in the refs to add to the USB stick. */ + g_autoptr(GPtrArray) refs = g_ptr_array_new_full (argc, (GDestroyNotify) ostree_collection_ref_free); + + for (gsize i = 2; i < argc; i += 2) + { + if (!ostree_validate_collection_id (argv[i], error) || + !ostree_validate_rev (argv[i + 1], error)) + return FALSE; + + g_ptr_array_add (refs, ostree_collection_ref_new (argv[i], argv[i + 1])); + } + + /* Open the destination repository on the USB stick or create it if it doesn’t exist. + * Check it’s below @mount_root_path, and that it’s not the same as the source + * repository. */ + const char *dest_repo_path = (opt_destination_repo != NULL) ? opt_destination_repo : ".ostree/repo"; + + if (!glnx_shutil_mkdir_p_at (mount_root_dfd, dest_repo_path, 0755, cancellable, error)) + return FALSE; + + /* Always use the archive repo mode, which works on FAT file systems that + * don't support xattrs, compresses files to save space, doesn't store + * permission info directly in the file attributes, and is at least sometimes + * more performant than bare-user */ + OstreeRepoMode mode = OSTREE_REPO_MODE_ARCHIVE; + + g_debug ("%s: Creating repository in mode %u", G_STRFUNC, mode); + + g_autoptr(OstreeRepo) dest_repo = ostree_repo_create_at (mount_root_dfd, dest_repo_path, + mode, NULL, cancellable, error); + + if (dest_repo == NULL) + return FALSE; + + struct stat dest_repo_stbuf; + + if (!glnx_fstat (ostree_repo_get_dfd (dest_repo), &dest_repo_stbuf, error)) + return FALSE; + + if (dest_repo_stbuf.st_dev != mount_root_stbuf.st_dev) + { + ot_util_usage_error (context, "--destination-repo must be a descendent of MOUNT-PATH", error); + return FALSE; + } + + if (ostree_repo_equal (src_repo, dest_repo)) + { + ot_util_usage_error (context, "--destination-repo must not be the source repository", error); + return FALSE; + } + + if (!ostree_ensure_repo_writable (dest_repo, error)) + return FALSE; + + if (opt_disable_fsync) + ostree_repo_set_disable_fsync (dest_repo, TRUE); + + /* Copy across all of the collection–refs to the destination repo. */ + GVariantBuilder refs_builder; + g_variant_builder_init (&refs_builder, G_VARIANT_TYPE ("a(sss)")); + + for (gsize i = 0; i < refs->len; i++) + { + const OstreeCollectionRef *ref = g_ptr_array_index (refs, i); + + g_variant_builder_add (&refs_builder, "(sss)", + ref->collection_id, ref->ref_name, opt_commit ?: ""); + } + + { + GVariantBuilder builder; + g_autoptr(GVariant) opts = NULL; + OstreeRepoPullFlags flags = OSTREE_REPO_PULL_FLAGS_MIRROR; + + glnx_console_lock (&console); + + if (console.is_tty) + progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + g_variant_builder_add (&builder, "{s@v}", "collection-refs", + g_variant_new_variant (g_variant_builder_end (&refs_builder))); + g_variant_builder_add (&builder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (flags))); + g_variant_builder_add (&builder, "{s@v}", "depth", + g_variant_new_variant (g_variant_new_int32 (0))); + opts = g_variant_ref_sink (g_variant_builder_end (&builder)); + + g_autofree char *src_repo_uri = g_file_get_uri (ostree_repo_get_path (src_repo)); + + if (!ostree_repo_pull_with_options (dest_repo, src_repo_uri, + opts, + progress, + cancellable, error)) + { + ostree_repo_abort_transaction (dest_repo, cancellable, NULL); + return FALSE; + } + + if (progress != NULL) + ostree_async_progress_finish (progress); + } + + /* Ensure a summary file is present to make it easier to look up commit checksums. */ + /* FIXME: It should be possible to work without this, but find_remotes_cb() in + * ostree-repo-pull.c currently assumes a summary file (signed or unsigned) is + * present. */ + if (!ostree_repo_regenerate_summary (dest_repo, NULL, cancellable, error)) + return FALSE; + + /* Add the symlinks .ostree/repos.d/@symlink_name → @dest_repo_path, unless + * the @dest_repo_path is a well-known one like ostree/repo, in which case no + * symlink is necessary; #OstreeRepoFinderMount always looks there. */ + if (!g_str_equal (dest_repo_path, "ostree/repo") && + !g_str_equal (dest_repo_path, ".ostree/repo")) + { + if (!glnx_shutil_mkdir_p_at (mount_root_dfd, ".ostree/repos.d", 0755, cancellable, error)) + return FALSE; + + /* Find a unique name for the symlink. If a symlink already targets + * @dest_repo_path, use that and don’t create a new one. */ + GLnxDirFdIterator repos_iter; + gboolean need_symlink = TRUE; + + if (!glnx_dirfd_iterator_init_at (mount_root_dfd, ".ostree/repos.d", TRUE, &repos_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *repo_dent; + + if (!glnx_dirfd_iterator_next_dent (&repos_iter, &repo_dent, cancellable, error)) + return FALSE; + + if (repo_dent == NULL) + break; + + /* Does the symlink already point to this repository? (Or is the + * repository itself present in repos.d?) We already guarantee that + * they’re on the same device. */ + if (repo_dent->d_ino == dest_repo_stbuf.st_ino) + { + need_symlink = FALSE; + break; + } + } + + /* If we need a symlink, find a unique name for it and create it. */ + if (need_symlink) + { + /* Relative to .ostree/repos.d. */ + g_autofree char *relative_dest_repo_path = g_build_filename ("..", "..", dest_repo_path, NULL); + guint i; + const guint max_attempts = 100; + + for (i = 0; i < max_attempts; i++) + { + g_autofree char *symlink_path = g_strdup_printf (".ostree/repos.d/%02u-generated", i); + + int ret = TEMP_FAILURE_RETRY (symlinkat (relative_dest_repo_path, mount_root_dfd, symlink_path)); + if (ret < 0 && errno != EEXIST) + return glnx_throw_errno_prefix (error, "symlinkat(%s → %s)", symlink_path, relative_dest_repo_path); + else if (ret >= 0) + break; + } + + if (i == max_attempts) + return glnx_throw (error, "Could not find an unused symlink name for the repository"); + } + } + + /* Report success to the user. */ + g_autofree char *src_repo_path = g_file_get_path (ostree_repo_get_path (src_repo)); + + g_print ("Copied %u/%u refs successfully from ‘%s’ to ‘%s’ repository in ‘%s’.\n", refs->len, refs->len, + src_repo_path, dest_repo_path, mount_root_path); + + return TRUE; +} diff --git a/src/ostree/ot-builtin-diff.c b/src/ostree/ot-builtin-diff.c new file mode 100644 index 0000000..82a533d --- /dev/null +++ b/src/ostree/ot-builtin-diff.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +static gboolean opt_stats; +static gboolean opt_fs_diff; +static gboolean opt_no_xattrs; +static gint opt_owner_uid = -1; +static gint opt_owner_gid = -1; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-diff.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "stats", 0, 0, G_OPTION_ARG_NONE, &opt_stats, "Print various statistics", NULL }, + { "fs-diff", 0, 0, G_OPTION_ARG_NONE, &opt_fs_diff, "Print filesystem diff", NULL }, + { "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Skip output of extended attributes", NULL }, + { "owner-uid", 0, 0, G_OPTION_ARG_INT, &opt_owner_uid, "Use file ownership user id for local files", "UID" }, + { "owner-gid", 0, 0, G_OPTION_ARG_INT, &opt_owner_gid, "Use file ownership group id for local files", "GID" }, + { NULL } +}; + +static gboolean +parse_file_or_commit (OstreeRepo *repo, + const char *arg, + GFile **out_file, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GFile) ret_file = NULL; + + if (g_str_has_prefix (arg, "/") + || g_str_has_prefix (arg, "./") + ) + { + ret_file = g_file_new_for_path (arg); + } + else + { + if (!ostree_repo_read_commit (repo, arg, &ret_file, NULL, cancellable, error)) + goto out; + } + + ret = TRUE; + ot_transfer_out_value (out_file, &ret_file); + out: + return ret; +} + +static GHashTable * +reachable_set_intersect (GHashTable *a, GHashTable *b) +{ + GHashTable *ret = ostree_repo_traverse_new_reachable (); + GHashTableIter hashiter; + gpointer key, value; + + g_hash_table_iter_init (&hashiter, a); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + GVariant *v = key; + if (g_hash_table_contains (b, v)) + g_hash_table_insert (ret, g_variant_ref (v), v); + } + + return ret; +} + +static gboolean +object_set_total_size (OstreeRepo *repo, + GHashTable *reachable, + guint64 *out_total, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GHashTableIter hashiter; + gpointer key, value; + + *out_total = 0; + + g_hash_table_iter_init (&hashiter, reachable); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + GVariant *v = key; + const char *csum; + OstreeObjectType objtype; + guint64 size; + + ostree_object_name_deserialize (v, &csum, &objtype); + if (!ostree_repo_query_object_storage_size (repo, objtype, csum, &size, + cancellable, error)) + goto out; + *out_total += size; + } + + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_builtin_diff (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + const char *src; + const char *target; + g_autofree char *src_prev = NULL; + g_autoptr(GFile) srcf = NULL; + g_autoptr(GFile) targetf = NULL; + g_autoptr(GPtrArray) modified = NULL; + g_autoptr(GPtrArray) removed = NULL; + g_autoptr(GPtrArray) added = NULL; + + context = g_option_context_new ("REV_OR_DIR REV_OR_DIR"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + gchar *help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s\n", help); + g_free (help); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "REV must be specified"); + goto out; + } + + if (argc == 2) + { + src_prev = g_strconcat (argv[1], "^", NULL); + src = src_prev; + target = argv[1]; + } + else + { + src = argv[1]; + target = argv[2]; + } + + if (!opt_stats && !opt_fs_diff) + opt_fs_diff = TRUE; + + if (opt_fs_diff) + { + OstreeDiffFlags diff_flags = OSTREE_DIFF_FLAGS_NONE; + + if (opt_no_xattrs) + diff_flags |= OSTREE_DIFF_FLAGS_IGNORE_XATTRS; + + if (!parse_file_or_commit (repo, src, &srcf, cancellable, error)) + goto out; + if (!parse_file_or_commit (repo, target, &targetf, cancellable, error)) + goto out; + + modified = g_ptr_array_new_with_free_func ((GDestroyNotify)ostree_diff_item_unref); + removed = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + added = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + + OstreeDiffDirsOptions diff_opts = { opt_owner_uid, opt_owner_gid }; + if (!ostree_diff_dirs_with_options (diff_flags, srcf, targetf, modified, removed, + added, &diff_opts, cancellable, error)) + goto out; + + ostree_diff_print (srcf, targetf, modified, removed, added); + } + + if (opt_stats) + { + g_autoptr(GHashTable) reachable_a = NULL; + g_autoptr(GHashTable) reachable_b = NULL; + g_autoptr(GHashTable) reachable_intersection = NULL; + g_autofree char *rev_a = NULL; + g_autofree char *rev_b = NULL; + g_autofree char *size = NULL; + guint a_size; + guint b_size; + guint64 total_common; + + if (!ostree_repo_resolve_rev (repo, src, FALSE, &rev_a, error)) + goto out; + if (!ostree_repo_resolve_rev (repo, target, FALSE, &rev_b, error)) + goto out; + + if (!ostree_repo_traverse_commit (repo, rev_a, 0, &reachable_a, cancellable, error)) + goto out; + if (!ostree_repo_traverse_commit (repo, rev_b, 0, &reachable_b, cancellable, error)) + goto out; + + a_size = g_hash_table_size (reachable_a); + b_size = g_hash_table_size (reachable_b); + g_print ("[A] Object Count: %u\n", a_size); + g_print ("[B] Object Count: %u\n", b_size); + + reachable_intersection = reachable_set_intersect (reachable_a, reachable_b); + + g_print ("Common Object Count: %u\n", g_hash_table_size (reachable_intersection)); + + if (!object_set_total_size (repo, reachable_intersection, &total_common, + cancellable, error)) + goto out; + size = g_format_size_full (total_common, 0); + g_print ("Common Object Size: %s\n", size); + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-builtin-export.c b/src/ostree/ot-builtin-export.c new file mode 100644 index 0000000..0f0755e --- /dev/null +++ b/src/ostree/ot-builtin-export.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2016 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree-libarchive-private.h" +#include "ostree.h" +#include "ostree-repo-file.h" + +#ifdef HAVE_LIBARCHIVE +#include +#include +#endif + +static char *opt_output_path; +static char *opt_subpath; +static char *opt_prefix; +static gboolean opt_no_xattrs; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-export.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Skip output of extended attributes", NULL }, + { "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, + { "prefix", 0, 0, G_OPTION_ARG_FILENAME, &opt_prefix, "Add PATH as prefix to archive pathnames", "PATH" }, + { "output", 'o', 0, G_OPTION_ARG_FILENAME, &opt_output_path, "Output to PATH ", "PATH" }, + { NULL } +}; + +#ifdef HAVE_LIBARCHIVE + +static void +propagate_libarchive_error (GError **error, + struct archive *a) +{ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", archive_error_string (a)); +} + +#endif + +gboolean +ostree_builtin_export (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + gboolean ret = FALSE; + g_autoptr(GFile) root = NULL; + g_autoptr(GFile) subtree = NULL; + g_autofree char *commit = NULL; + g_autoptr(GVariant) commit_data = NULL; +#ifdef HAVE_LIBARCHIVE + const char *rev; + g_autoptr(OtAutoArchiveWrite) a = NULL; + OstreeRepoExportArchiveOptions opts = { 0, }; +#endif + + context = g_option_context_new ("COMMIT"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + +#ifdef HAVE_LIBARCHIVE + + if (argc <= 1) + { + ot_util_usage_error (context, "A COMMIT argument is required", error); + goto out; + } + rev = argv[1]; + + a = archive_write_new (); + /* Yes, this is hardcoded for now. There is + * archive_write_set_format_filter_by_ext() but it's fairly magic. + * Many programs have support now for GNU tar, so should be a good + * default. I also don't want to lock us into everything libarchive + * supports. + */ + if (archive_write_set_format_gnutar (a) != ARCHIVE_OK) + { + propagate_libarchive_error (error, a); + goto out; + } + if (archive_write_add_filter_none (a) != ARCHIVE_OK) + { + propagate_libarchive_error (error, a); + goto out; + } + if (opt_output_path) + { + if (archive_write_open_filename (a, opt_output_path) != ARCHIVE_OK) + { + propagate_libarchive_error (error, a); + goto out; + } + } + else + { + if (archive_write_open_FILE (a, stdout) != ARCHIVE_OK) + { + propagate_libarchive_error (error, a); + goto out; + } + } + + if (opt_no_xattrs) + opts.disable_xattrs = TRUE; + + if (!ostree_repo_read_commit (repo, rev, &root, &commit, cancellable, error)) + goto out; + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, commit, &commit_data, error)) + goto out; + + opts.timestamp_secs = ostree_commit_get_timestamp (commit_data); + + if (opt_subpath) + subtree = g_file_resolve_relative_path (root, opt_subpath); + else + subtree = g_object_ref (root); + + opts.path_prefix = opt_prefix; + + if (!ostree_repo_export_tree_to_archive (repo, &opts, (OstreeRepoFile*)subtree, a, + cancellable, error)) + goto out; + + if (archive_write_close (a) != ARCHIVE_OK) + { + propagate_libarchive_error (error, a); + goto out; + } + +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree is not compiled with libarchive support"); + goto out; +#endif + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-builtin-find-remotes.c b/src/ostree/ot-builtin-find-remotes.c new file mode 100644 index 0000000..944533c --- /dev/null +++ b/src/ostree/ot-builtin-find-remotes.c @@ -0,0 +1,405 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +#include "ostree-remote-private.h" + +static gchar *opt_cache_dir = NULL; +static gchar *opt_finders = NULL; +static gboolean opt_disable_fsync = FALSE; +static gboolean opt_pull = FALSE; +static gboolean opt_mirror = FALSE; + +static GOptionEntry options[] = + { + { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, + { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, + { "finders", 0, 0, G_OPTION_ARG_STRING, &opt_finders, "Use the specified comma separated list of finders (e.g. config,lan,mount)", "FINDERS" }, + { "pull", 0, 0, G_OPTION_ARG_NONE, &opt_pull, "Pull the updates after finding them", NULL }, + { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Do a mirror pull (see ostree pull --mirror)", NULL}, + { NULL } + }; + +static gchar * +uint64_secs_to_iso8601 (guint64 secs) +{ + g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (secs); + + if (dt != NULL) + return g_date_time_format (dt, "%FT%TZ"); + else + return g_strdup ("invalid"); +} + +static gchar * +format_ref_to_checksum (GHashTable *ref_to_checksum /* (element-type OstreeCollectionRef utf8) */, + const gchar *line_prefix) +{ + GHashTableIter iter; + const OstreeCollectionRef *ref; + const gchar *checksum; + g_autoptr(GString) out = NULL; + + g_hash_table_iter_init (&iter, ref_to_checksum); + out = g_string_new (""); + + while (g_hash_table_iter_next (&iter, (gpointer *) &ref, (gpointer *) &checksum)) + g_string_append_printf (out, "%s - (%s, %s) = %s\n", + line_prefix, ref->collection_id, ref->ref_name, + (checksum != NULL) ? checksum : "(not found)"); + + return g_string_free (g_steal_pointer (&out), FALSE); +} + +static gchar * +remote_get_uri (OstreeRemote *remote) +{ + g_autoptr(GError) error = NULL; + g_autofree gchar *uri = NULL; + + uri = g_key_file_get_string (remote->options, remote->group, "url", &error); + g_assert_no_error (error); + + return g_steal_pointer (&uri); +} + +/* Add each key from @keys_input to @set iff its value is non-%NULL. */ +static void +add_keys_to_set_if_non_null (GHashTable *set, + GHashTable *keys_input) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init (&iter, keys_input); + + while (g_hash_table_iter_next (&iter, &key, &value)) + if (value != NULL) + g_hash_table_add (set, key); +} + +static void +get_result_cb (GObject *obj, + GAsyncResult *result, + gpointer user_data) +{ + GAsyncResult **result_out = user_data; + *result_out = g_object_ref (result); +} + +static void +collection_ref_free0 (OstreeCollectionRef *ref) +{ + if (ref == NULL) + return; + ostree_collection_ref_free (ref); +} + +static gboolean +validate_finders_list (const char **finders, + GOptionContext *context, + GError **error) +{ + typedef struct { + gchar *finder_name; + gboolean already_used; + } Finder; + Finder valid_finders[] = { + {.finder_name = "config", .already_used = FALSE}, + {.finder_name = "lan", .already_used = FALSE}, + {.finder_name = "mount", .already_used = FALSE} + }; + + if (finders == NULL || *finders == NULL) + { + ot_util_usage_error (context, "List of finders in --finders option must not be empty", error); + return FALSE; + } + + for (const char **iter = finders; iter && *iter; iter++) + { + gboolean is_valid_finder = FALSE; + for (unsigned int i = 0; i < G_N_ELEMENTS (valid_finders); i++) + { + if (valid_finders[i].already_used == TRUE) + continue; + if (g_strcmp0 (*iter, valid_finders[i].finder_name) == 0) + { + is_valid_finder = TRUE; + valid_finders[i].already_used = TRUE; + } + } + if (!is_valid_finder) + { + g_autofree gchar *error_msg = NULL; + error_msg = g_strdup_printf ("Unknown or duplicate finder type given in --finders option: ‘%s’", *iter); + ot_util_usage_error (context, error_msg, error); + return FALSE; + } + } + + return TRUE; +} + +gboolean +ostree_builtin_find_remotes (int argc, + char **argv, + OstreeCommandInvocation *invocation, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GPtrArray) refs = NULL; /* (element-type OstreeCollectionRef) */ + g_autoptr(GPtrArray) finders = NULL; /* (element-type OstreeRepoFinder) */ + g_autoptr(OstreeRepoFinder) finder_config = NULL; + g_autoptr(OstreeRepoFinder) finder_mount = NULL; +#ifdef HAVE_AVAHI + g_autoptr(OstreeRepoFinder) finder_avahi = NULL; +#endif /* HAVE_AVAHI */ + g_autoptr(OstreeAsyncProgress) progress = NULL; + gsize i; + g_autoptr(GAsyncResult) find_result = NULL, pull_result = NULL; + g_auto(OstreeRepoFinderResultv) results = NULL; + g_auto(GLnxConsoleRef) console = { 0, }; + g_autoptr(GHashTable) refs_found = NULL; /* set (element-type OstreeCollectionRef) */ + g_autoptr(GVariant) pull_options = NULL; + + context = g_option_context_new ("COLLECTION-ID REF [COLLECTION-ID REF...]"); + + /* Parse options. */ + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (!ostree_ensure_repo_writable (repo, error)) + return FALSE; + + if (argc < 3) + { + ot_util_usage_error (context, "At least one COLLECTION-ID REF pair must be specified", error); + return FALSE; + } + + if (argc % 2 == 0) + { + ot_util_usage_error (context, "Only complete COLLECTION-ID REF pairs may be specified", error); + return FALSE; + } + + if (opt_mirror && !opt_pull) + { + ot_util_usage_error (context, "When --mirror is specified, --pull must also be", error); + return FALSE; + } + + if (opt_disable_fsync) + ostree_repo_set_disable_fsync (repo, TRUE); + + if (opt_cache_dir && + !ostree_repo_set_cache_dir (repo, AT_FDCWD, opt_cache_dir, cancellable, error)) + return FALSE; + + /* Read in the refs to search for remotes for. */ + refs = g_ptr_array_new_full (argc, (GDestroyNotify) collection_ref_free0); + + for (i = 1; i < argc; i += 2) + { + if (!ostree_validate_collection_id (argv[i], error) || + !ostree_validate_rev (argv[i + 1], error)) + return FALSE; + + g_ptr_array_add (refs, ostree_collection_ref_new (argv[i], argv[i + 1])); + } + + g_ptr_array_add (refs, NULL); + + /* Build the array of OstreeRepoFinder instances */ + if (opt_finders != NULL) + { + g_auto(GStrv) finders_strings = NULL; + + finders_strings = g_strsplit (opt_finders, ",", 0); + if (!validate_finders_list ((const char **)finders_strings, context, error)) + return FALSE; + + finders = g_ptr_array_new_with_free_func (NULL); + for (const char **iter = (const char **)finders_strings; iter && *iter; iter++) + { + if (g_strcmp0 (*iter, "config") == 0) + { + finder_config = OSTREE_REPO_FINDER (ostree_repo_finder_config_new ()); + g_ptr_array_add (finders, finder_config); + } + else if (g_strcmp0 (*iter, "mount") == 0) + { + finder_mount = OSTREE_REPO_FINDER (ostree_repo_finder_mount_new (NULL)); + g_ptr_array_add (finders, finder_mount); + } + else if (g_strcmp0 (*iter, "lan") == 0) + { +#ifdef HAVE_AVAHI + GMainContext *main_context = g_main_context_get_thread_default (); + g_autoptr(GError) local_error = NULL; + + finder_avahi = OSTREE_REPO_FINDER (ostree_repo_finder_avahi_new (main_context)); + ostree_repo_finder_avahi_start (OSTREE_REPO_FINDER_AVAHI (finder_avahi), &local_error); + + if (local_error != NULL) + { + g_warning ("Avahi finder failed; removing it: %s", local_error->message); + g_clear_object (&finder_avahi); + } + else + g_ptr_array_add (finders, finder_avahi); +#else + ot_util_usage_error (context, "LAN repo finder requested but ostree was compiled without Avahi support", error); + return FALSE; +#endif /* HAVE_AVAHI */ + } + else + g_assert_not_reached (); + } + g_ptr_array_add (finders, NULL); + } + + /* Run the operation. */ + glnx_console_lock (&console); + + if (console.is_tty) + progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); + + ostree_repo_find_remotes_async (repo, + (const OstreeCollectionRef * const *) refs->pdata, + NULL /* no options */, + finders != NULL ? (OstreeRepoFinder **) finders->pdata : NULL, + progress, cancellable, + get_result_cb, &find_result); + + while (find_result == NULL) + g_main_context_iteration (NULL, TRUE); + + results = ostree_repo_find_remotes_finish (repo, find_result, error); + + if (results == NULL) + return FALSE; + + if (progress) + ostree_async_progress_finish (progress); + + /* Print results and work out which refs were not found. */ + refs_found = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, NULL, NULL); + + for (i = 0; results[i] != NULL; i++) + { + g_autofree gchar *uri = NULL; + g_autofree gchar *refs_string = NULL; + g_autofree gchar *last_modified_string = NULL; + + uri = remote_get_uri (results[i]->remote); + refs_string = format_ref_to_checksum (results[i]->ref_to_checksum, " "); + add_keys_to_set_if_non_null (refs_found, results[i]->ref_to_checksum); + + if (results[i]->summary_last_modified > 0) + last_modified_string = uint64_secs_to_iso8601 (results[i]->summary_last_modified); + else + last_modified_string = g_strdup ("unknown"); + + g_print ("Result %" G_GSIZE_FORMAT ": %s\n" + " - Finder: %s\n" + " - Keyring: %s\n" + " - Priority: %d\n" + " - Summary last modified: %s\n" + " - Refs:\n" + "%s\n", + i, uri, G_OBJECT_TYPE_NAME (results[i]->finder), results[i]->remote->keyring, + results[i]->priority, last_modified_string, refs_string); + } + + if (results[0] == NULL) + { + g_print ("No results.\n"); + return TRUE; + } + + g_print ("%u/%u refs were found.\n", g_hash_table_size (refs_found), refs->len - 1); + + /* Print out the refs which weren’t found. */ + if (g_hash_table_size (refs_found) != refs->len - 1 /* NULL terminator */) + { + g_print ("Refs not found in any remote:\n"); + + for (i = 0; i < refs->len && refs->pdata[i] != NULL; i++) + { + const OstreeCollectionRef *ref = g_ptr_array_index (refs, i); + if (!g_hash_table_contains (refs_found, ref)) + g_print (" - (%s, %s)\n", ref->collection_id, ref->ref_name); + } + } + + /* Does the user want us to pull the updates? */ + if (!opt_pull) + return TRUE; + + { + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + if (opt_mirror) + g_variant_builder_add (&builder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (OSTREE_REPO_PULL_FLAGS_MIRROR))); + + pull_options = g_variant_ref_sink (g_variant_builder_end (&builder)); + } + + /* Run the pull operation. */ + if (console.is_tty) + progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); + + ostree_repo_pull_from_remotes_async (repo, + (const OstreeRepoFinderResult * const *) results, + pull_options, + progress, cancellable, + get_result_cb, &pull_result); + + while (pull_result == NULL) + g_main_context_iteration (NULL, TRUE); + + if (!ostree_repo_pull_from_remotes_finish (repo, pull_result, error)) + return FALSE; + + if (progress) + ostree_async_progress_finish (progress); + + /* The pull operation fails if any of the refs can’t be pulled. */ + g_print ("Pulled %u/%u refs successfully.\n", refs->len - 1, refs->len - 1); + + return TRUE; +} diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c new file mode 100644 index 0000000..dea03af --- /dev/null +++ b/src/ostree/ot-builtin-fsck.c @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "ostree-cmdprivate.h" +#include "otutil.h" + +static gboolean opt_quiet; +static gboolean opt_delete; +static gboolean opt_all; +static gboolean opt_add_tombstones; +static gboolean opt_verify_bindings; +static gboolean opt_verify_back_refs; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-fsck.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "add-tombstones", 0, 0, G_OPTION_ARG_NONE, &opt_add_tombstones, "Add tombstones for missing commits", NULL }, + { "quiet", 'q', 0, G_OPTION_ARG_NONE, &opt_quiet, "Only print error messages", NULL }, + { "all", 'a', 0, G_OPTION_ARG_NONE, &opt_all, "Don't stop on first error", NULL }, + { "delete", 0, 0, G_OPTION_ARG_NONE, &opt_delete, "Remove corrupted objects", NULL }, + { "verify-bindings", 0, 0, G_OPTION_ARG_NONE, &opt_verify_bindings, "Verify ref bindings", NULL }, + { "verify-back-refs", 0, 0, G_OPTION_ARG_NONE, &opt_verify_back_refs, "Verify back-references (implies --verify-bindings)", NULL }, + { NULL } +}; + +static gboolean +fsck_one_object (OstreeRepo *repo, + const char *checksum, + OstreeObjectType objtype, + GHashTable *object_parents, + GVariant *key, + gboolean *out_found_corruption, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GError) temp_error = NULL; + if (!ostree_repo_fsck_object (repo, objtype, checksum, cancellable, &temp_error)) + { + gboolean object_missing = FALSE; + g_auto(GStrv) parent_commits = NULL; + g_autofree char *parent_commits_str = NULL; + + if (object_parents) + { + parent_commits = ostree_repo_traverse_parents_get_commits (object_parents, key); + parent_commits_str = g_strjoinv (", ", parent_commits); + } + + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&temp_error); + if (parent_commits_str) + g_printerr ("Object missing in commits %s: %s.%s\n", parent_commits_str, checksum, + ostree_object_type_to_string (objtype)); + else + g_printerr ("Object missing: %s.%s\n", checksum, + ostree_object_type_to_string (objtype)); + object_missing = TRUE; + } + else + { + if (parent_commits_str) + g_prefix_error (&temp_error, "In commits %s: ", parent_commits_str); + + if (opt_delete) + { + g_printerr ("%s\n", temp_error->message); + (void) ostree_repo_delete_object (repo, objtype, checksum, cancellable, NULL); + object_missing = TRUE; + } + else if (opt_all) + { + *out_found_corruption = TRUE; + g_printerr ("%s\n", temp_error->message); + } + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + return FALSE; + } + } + + if (object_missing) + { + *out_found_corruption = TRUE; + + if (parent_commits != NULL && objtype != OSTREE_OBJECT_TYPE_COMMIT) + { + int i; + + /* The commit was missing or deleted, mark the commit partial */ + for (i = 0; parent_commits[i] != NULL; i++) + { + const char *parent_commit = parent_commits[i]; + OstreeRepoCommitState state; + if (!ostree_repo_load_commit (repo, parent_commit, NULL, + &state, error)) + return FALSE; + if ((state & OSTREE_REPO_COMMIT_STATE_PARTIAL) == 0) + { + g_printerr ("Marking commit as partial: %s\n", parent_commit); + if (!ostree_repo_mark_commit_partial_reason (repo, parent_commit, TRUE, OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL, error)) + return FALSE; + } + } + } + } + } + + return TRUE; +} + +static gboolean +fsck_reachable_objects_from_commits (OstreeRepo *repo, + GHashTable *commits, + gboolean *out_found_corruption, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GHashTable) reachable_objects = ostree_repo_traverse_new_reachable (); + g_autoptr(GHashTable) object_parents = ostree_repo_traverse_new_parents (); + + GHashTableIter hash_iter; + gpointer key, value; + g_hash_table_iter_init (&hash_iter, commits); + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + GVariant *serialized_key = key; + const char *checksum; + OstreeObjectType objtype; + + ostree_object_name_deserialize (serialized_key, &checksum, &objtype); + + g_assert (objtype == OSTREE_OBJECT_TYPE_COMMIT); + + if (!ostree_repo_traverse_commit_union_with_parents (repo, checksum, 0, reachable_objects, object_parents, + cancellable, error)) + return FALSE; + } + + g_auto(GLnxConsoleRef) console = { 0, }; + glnx_console_lock (&console); + + const guint count = g_hash_table_size (reachable_objects); + guint i = 0; + g_hash_table_iter_init (&hash_iter, reachable_objects); + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + GVariant *serialized_key = key; + const char *checksum; + OstreeObjectType objtype; + + ostree_object_name_deserialize (serialized_key, &checksum, &objtype); + + if (!fsck_one_object (repo, checksum, objtype, + object_parents, serialized_key, + out_found_corruption, cancellable, error)) + return FALSE; + + i++; + glnx_console_progress_n_items ("fsck objects", i, count); + } + + return TRUE; +} + +/* Check that a given commit object is valid for the ref it was looked up via. + * @collection_id will be %NULL for normal refs, and non-%NULL for collection–refs. */ +static gboolean +fsck_commit_for_ref (OstreeRepo *repo, + const char *checksum, + const char *collection_id, + const char *ref_name, + gboolean *found_corruption, + GCancellable *cancellable, + GError **error) +{ + if (!fsck_one_object (repo, checksum, OSTREE_OBJECT_TYPE_COMMIT, + NULL, NULL, found_corruption, + cancellable, error)) + return FALSE; + + /* Check the commit exists. */ + g_autoptr(GVariant) commit = NULL; + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + checksum, &commit, error)) + { + if (collection_id != NULL) + return glnx_prefix_error (error, "Loading commit for ref (%s, %s)", + collection_id, ref_name); + else + return glnx_prefix_error (error, "Loading commit for ref %s", ref_name); + } + + /* Check its bindings. */ + if (opt_verify_bindings) + { + if (!ostree_cmd__private__ ()->ostree_repo_verify_bindings (collection_id, ref_name, commit, error)) + return glnx_prefix_error (error, "Commit %s", checksum); + } + + return TRUE; +} + +gboolean +ostree_builtin_fsck (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(OstreeRepo) repo = NULL; + gboolean found_corruption = FALSE; + + g_autoptr(GOptionContext) context = g_option_context_new (""); + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (!opt_quiet) + g_print ("Validating refs...\n"); + + /* Validate that the commit for each ref is available */ + g_autoptr(GHashTable) all_refs = NULL; + if (!ostree_repo_list_refs (repo, NULL, &all_refs, + cancellable, error)) + return FALSE; + + GHashTableIter hash_iter; + gpointer key, value; + g_hash_table_iter_init (&hash_iter, all_refs); + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + const char *refspec = key; + const char *checksum = value; + g_autofree char *ref_name = NULL; + if (!ostree_parse_refspec (refspec, NULL, &ref_name, error)) + return FALSE; + if (!fsck_commit_for_ref (repo, checksum, NULL, ref_name, + &found_corruption, cancellable, error)) + return FALSE; + } + + if (!opt_quiet) + g_print ("Validating refs in collections...\n"); + + g_autoptr(GHashTable) all_collection_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + if (!ostree_repo_list_collection_refs (repo, NULL, &all_collection_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, + cancellable, error)) + return FALSE; + + g_hash_table_iter_init (&hash_iter, all_collection_refs); + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + const OstreeCollectionRef *ref = key; + if (!fsck_commit_for_ref (repo, value, ref->collection_id, ref->ref_name, + &found_corruption, cancellable, error)) + return FALSE; + } + + if (!opt_quiet) + g_print ("Enumerating objects...\n"); + + g_autoptr(GHashTable) objects = NULL; + if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL, + &objects, cancellable, error)) + return FALSE; + + g_autoptr(GHashTable) commits = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, + (GDestroyNotify)g_variant_unref, NULL); + + + g_autoptr(GPtrArray) tombstones = NULL; + if (opt_add_tombstones) + tombstones = g_ptr_array_new_with_free_func (g_free); + + if (opt_verify_back_refs) + opt_verify_bindings = TRUE; + + guint n_partial = 0; + guint n_fsck_partial = 0; + g_hash_table_iter_init (&hash_iter, objects); + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + GVariant *serialized_key = key; + const char *checksum; + OstreeObjectType objtype; + OstreeRepoCommitState commitstate = 0; + g_autoptr(GVariant) commit = NULL; + + ostree_object_name_deserialize (serialized_key, &checksum, &objtype); + + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + if (!ostree_repo_load_commit (repo, checksum, &commit, &commitstate, error)) + return FALSE; + + /* If requested, check that all the refs listed in the ref-bindings + * for this commit resolve back to this commit. */ + if (opt_verify_back_refs) + { + g_autoptr(GVariant) metadata = g_variant_get_child_value (commit, 0); + + const char *collection_id = NULL; + if (!g_variant_lookup (metadata, + OSTREE_COMMIT_META_KEY_COLLECTION_BINDING, + "&s", + &collection_id)) + collection_id = NULL; + + g_autofree const char **refs = NULL; + if (g_variant_lookup (metadata, + OSTREE_COMMIT_META_KEY_REF_BINDING, + "^a&s", + &refs)) + { + for (const char **iter = refs; *iter != NULL; ++iter) + { + g_autofree char *checksum_for_ref = NULL; + + if (collection_id != NULL) + { + const OstreeCollectionRef collection_ref = { (char *) collection_id, (char *) *iter }; + if (!ostree_repo_resolve_collection_ref (repo, &collection_ref, + TRUE, + OSTREE_REPO_RESOLVE_REV_EXT_NONE, + &checksum_for_ref, + cancellable, + error)) + return FALSE; + } + else + { + if (!ostree_repo_resolve_rev (repo, *iter, TRUE, + &checksum_for_ref, error)) + return FALSE; + } + + if (checksum_for_ref == NULL) + { + if (collection_id != NULL) + return glnx_throw (error, + "Collection–ref (%s, %s) in bindings for commit %s does not exist", + collection_id, *iter, checksum); + else + return glnx_throw (error, + "Ref ‘%s’ in bindings for commit %s does not exist", + *iter, checksum); + } + else if (g_strcmp0 (checksum_for_ref, checksum) != 0) + { + if (collection_id != NULL) + return glnx_throw (error, + "Collection–ref (%s, %s) in bindings for commit %s does not resolve to that commit", + collection_id, *iter, checksum); + else + return glnx_throw (error, + "Ref ‘%s’ in bindings for commit %s does not resolve to that commit", + *iter, checksum); + } + } + } + } + + if (opt_add_tombstones) + { + GError *local_error = NULL; + g_autofree char *parent = ostree_commit_get_parent (commit); + if (parent) + { + g_autoptr(GVariant) parent_commit = NULL; + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, parent, + &parent_commit, &local_error)) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_ptr_array_add (tombstones, g_strdup (checksum)); + g_clear_error (&local_error); + } + else + { + g_propagate_error (error, local_error); + return FALSE; + } + } + } + } + + if (commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) + { + n_partial++; + if (commitstate & OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL) + n_fsck_partial++; + } + else + g_hash_table_add (commits, g_variant_ref (serialized_key)); + } + } + + g_clear_pointer (&objects, (GDestroyNotify) g_hash_table_unref); + + if (!opt_quiet) + g_print ("Verifying content integrity of %u commit objects...\n", + (guint)g_hash_table_size (commits)); + + if (!fsck_reachable_objects_from_commits (repo, commits, &found_corruption, + cancellable, error)) + return FALSE; + + if (opt_add_tombstones) + { + guint i; + g_assert (tombstones); /* Pacify static analysis */ + if (tombstones->len) + { + if (!ot_enable_tombstone_commits (repo, error)) + return FALSE; + } + for (i = 0; i < tombstones->len; i++) + { + const char *checksum = tombstones->pdata[i]; + g_print ("Adding tombstone for commit %s\n", checksum); + if (!ostree_repo_delete_object (repo, OSTREE_OBJECT_TYPE_COMMIT, checksum, cancellable, error)) + return FALSE; + } + } + else if (n_partial > 0) + { + g_print ("%u partial commits not verified\n", n_partial); + } + + if (found_corruption) + return glnx_throw (error, "Repository corruption encountered"); + + if (n_fsck_partial > 0) + return glnx_throw (error, "%u partial commits from fsck-detected corruption", n_partial); + + return TRUE; +} diff --git a/src/ostree/ot-builtin-gpg-sign.c b/src/ostree/ot-builtin-gpg-sign.c new file mode 100644 index 0000000..6babbf2 --- /dev/null +++ b/src/ostree/ot-builtin-gpg-sign.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2015 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" +#include "ostree-core-private.h" + +static gboolean opt_delete; +static char *opt_gpg_homedir; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-gpg-sign.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "delete", 'd', 0, G_OPTION_ARG_NONE, &opt_delete, "Delete signatures having any of the GPG KEY-IDs" }, + { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR" }, + { NULL } +}; + +static void +usage_error (GOptionContext *context, const char *message, GError **error) +{ + g_autofree char *help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s", help); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, message); +} + +static gboolean +delete_signatures (OstreeRepo *repo, + const char *commit_checksum, + const char * const *key_ids, + guint n_key_ids, + guint *out_n_deleted, + GCancellable *cancellable, + GError **error) +{ + GVariantDict metadata_dict; + g_autoptr(OstreeGpgVerifyResult) result = NULL; + g_autoptr(GVariant) old_metadata = NULL; + g_autoptr(GVariant) new_metadata = NULL; + g_autoptr(GVariant) signature_data = NULL; + GVariantIter iter; + GVariant *child; + GQueue signatures = G_QUEUE_INIT; + GQueue trash = G_QUEUE_INIT; + guint n_deleted = 0; + guint ii; + gboolean ret = FALSE; + GError *local_error = NULL; + + /* XXX Should this code be a new OstreeRepo function in libostree? + * Feels slightly too low-level here, and I have to know about + * the metadata key name and format which are both declared in + * ostree-core-private.h. + * + * OTOH, would this really be a useful addition to libostree? + */ + + if (!ostree_repo_read_commit_detached_metadata (repo, + commit_checksum, + &old_metadata, + cancellable, + error)) + goto out; + + g_variant_dict_init (&metadata_dict, old_metadata); + + signature_data = g_variant_dict_lookup_value (&metadata_dict, + _OSTREE_METADATA_GPGSIGS_NAME, + G_VARIANT_TYPE ("aay")); + + /* Taking the approach of deleting whatever matches we find for the + * provided key IDs, even if we don't find a match for EVERY key ID. + * So no signatures means no matches, which is okay... I guess. */ + if (signature_data == NULL) + { + g_variant_dict_clear (&metadata_dict); + goto shortcut; + } + + /* Parse the signatures on this commit by running a verify operation + * on it. Use the result to match key IDs to signatures for deletion. + * + * XXX Reading detached metadata from disk twice here. Another reason + * to move this into libostree? + */ + result = ostree_repo_verify_commit_ext (repo, commit_checksum, + NULL, NULL, + cancellable, &local_error); + if (result == NULL) + { + g_variant_dict_clear (&metadata_dict); + goto out; + } + + /* Convert the GVariant array to a GQueue. */ + g_variant_iter_init (&iter, signature_data); + while ((child = g_variant_iter_next_value (&iter)) != NULL) + { + /* Takes ownership of the child. */ + g_queue_push_tail (&signatures, child); + } + + /* Signature count and ordering of signatures in the GQueue and + * OstreeGpgVerifyResult must agree. We use this below to mark + * items in the GQueue for deletion based on the index returned + * by ostree_gpg_verify_result_lookup(). */ + g_assert_cmpuint (ostree_gpg_verify_result_count_all (result), ==, signatures.length); + + /* Build a trash queue which points at nodes in the signature queue. */ + for (ii = 0; ii < n_key_ids; ii++) + { + guint index; + + if (ostree_gpg_verify_result_lookup (result, key_ids[ii], &index)) + { + GList *link = g_queue_peek_nth_link (&signatures, index); + + /* Avoid duplicates in the trash queue. */ + if (g_queue_find (&trash, link) == NULL) + g_queue_push_tail (&trash, link); + } + } + + n_deleted = trash.length; + + /* Reduce the signature queue by emptying the trash. */ + while (!g_queue_is_empty (&trash)) + { + GList *link = g_queue_pop_head (&trash); + g_variant_unref (link->data); + g_queue_delete_link (&signatures, link); + } + + /* Update the metadata dictionary. */ + if (g_queue_is_empty (&signatures)) + { + g_variant_dict_remove (&metadata_dict, _OSTREE_METADATA_GPGSIGS_NAME); + } + else + { + GVariantBuilder signature_builder; + + g_variant_builder_init (&signature_builder, G_VARIANT_TYPE ("aay")); + + while (!g_queue_is_empty (&signatures)) + { + GVariant *child = g_queue_pop_head (&signatures); + g_variant_builder_add_value (&signature_builder, child); + g_variant_unref (child); + } + + g_variant_dict_insert_value (&metadata_dict, + _OSTREE_METADATA_GPGSIGS_NAME, + g_variant_builder_end (&signature_builder)); + } + + /* Commit the new metadata. */ + new_metadata = g_variant_dict_end (&metadata_dict); + if (!ostree_repo_write_commit_detached_metadata (repo, + commit_checksum, + new_metadata, + cancellable, + error)) + goto out; + +shortcut: + + if (out_n_deleted != NULL) + *out_n_deleted = n_deleted; + + ret = TRUE; + +out: + return ret; +} + +gboolean +ostree_builtin_gpg_sign (int argc, char **argv,OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_autofree char *resolved_commit = NULL; + const char *commit; + char **key_ids; + int n_key_ids, ii; + gboolean ret = FALSE; + + context = g_option_context_new ("COMMIT KEY-ID..."); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + usage_error (context, "Need a COMMIT to sign", error); + goto out; + } + + if (argc < 3) + { + usage_error (context, "Need at least one GPG KEY-ID to sign with", error); + goto out; + } + + commit = argv[1]; + key_ids = argv + 2; + n_key_ids = argc - 2; + + if (!ostree_repo_resolve_rev (repo, commit, FALSE, &resolved_commit, error)) + goto out; + + if (opt_delete) + { + guint n_deleted = 0; + + if (delete_signatures (repo, resolved_commit, + (const char * const *) key_ids, n_key_ids, + &n_deleted, cancellable, error)) + { + g_print ("Signatures deleted: %u\n", n_deleted); + ret = TRUE; + } + + goto out; + } + + for (ii = 0; ii < n_key_ids; ii++) + { + if (!ostree_repo_sign_commit (repo, resolved_commit, key_ids[ii], + opt_gpg_homedir, cancellable, error)) + goto out; + } + + ret = TRUE; + +out: + return ret; +} diff --git a/src/ostree/ot-builtin-init.c b/src/ostree/ot-builtin-init.c new file mode 100644 index 0000000..217bf31 --- /dev/null +++ b/src/ostree/ot-builtin-init.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" + +static char *opt_mode = "bare"; +static char *opt_collection_id = NULL; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-init.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "mode", 0, 0, G_OPTION_ARG_STRING, &opt_mode, "Initialize repository in given mode (bare, bare-user, bare-user-only, archive)", NULL }, + { "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id, + "Globally unique ID for this repository as an collection of refs for redistribution to other repositories", "COLLECTION-ID" }, + { NULL } +}; + +gboolean +ostree_builtin_init (int argc, char **argv,OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + gboolean ret = FALSE; + OstreeRepoMode mode; + + context = g_option_context_new (""); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (!ostree_repo_mode_from_string (opt_mode, &mode, error)) + goto out; + if (!ostree_repo_set_collection_id (repo, opt_collection_id, error)) + goto out; + + if (!ostree_repo_create (repo, mode, NULL, error)) + goto out; + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-builtin-log.c b/src/ostree/ot-builtin-log.c new file mode 100644 index 0000000..306f177 --- /dev/null +++ b/src/ostree/ot-builtin-log.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2013 Stef Walter + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Stef Walter + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ot-dump.h" +#include "ostree.h" +#include "otutil.h" + +static gboolean opt_raw; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-log.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data" }, + { NULL } +}; + +static gboolean +log_commit (OstreeRepo *repo, + const gchar *checksum, + gboolean is_recurse, + OstreeDumpFlags flags, + GError **error) +{ + g_autoptr(GVariant) variant = NULL; + g_autofree char *parent = NULL; + gboolean ret = FALSE; + GError *local_error = NULL; + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, checksum, + &variant, &local_error)) + { + if (is_recurse && g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_print ("<< History beyond this commit not fetched >>\n"); + g_clear_error (&local_error); + ret = TRUE; + } + else + { + g_propagate_error (error, local_error); + } + goto out; + } + + ot_dump_object (OSTREE_OBJECT_TYPE_COMMIT, checksum, variant, flags); + + /* Get the parent of this commit */ + parent = ostree_commit_get_parent (variant); + if (parent && !log_commit (repo, parent, TRUE, flags, error)) + goto out; + + ret = TRUE; +out: + return ret; +} + +gboolean +ostree_builtin_log (int argc, + char **argv, + OstreeCommandInvocation *invocation, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + gboolean ret = FALSE; + const char *rev; + g_autofree char *checksum = NULL; + OstreeDumpFlags flags = OSTREE_DUMP_NONE; + + context = g_option_context_new ("REF"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (opt_raw) + flags |= OSTREE_DUMP_RAW; + + if (argc <= 1) + { + ot_util_usage_error (context, "A ref argument is required", error); + goto out; + } + rev = argv[1]; + + if (!ostree_repo_resolve_rev (repo, rev, FALSE, &checksum, error)) + goto out; + + if (!log_commit (repo, checksum, FALSE, flags, error)) + goto out; + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-builtin-ls.c b/src/ostree/ot-builtin-ls.c new file mode 100644 index 0000000..baede0d --- /dev/null +++ b/src/ostree/ot-builtin-ls.c @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "ostree-repo-file.h" +#include "otutil.h" + +static gboolean opt_dironly; +static gboolean opt_recursive; +static gboolean opt_checksum; +static gboolean opt_xattrs; +static gboolean opt_nul_filenames_only; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-ls.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "dironly", 'd', 0, G_OPTION_ARG_NONE, &opt_dironly, "Do not recurse into directory arguments", NULL }, + { "recursive", 'R', 0, G_OPTION_ARG_NONE, &opt_recursive, "Print directories recursively", NULL }, + { "checksum", 'C', 0, G_OPTION_ARG_NONE, &opt_checksum, "Print checksum", NULL }, + { "xattrs", 'X', 0, G_OPTION_ARG_NONE, &opt_xattrs, "Print extended attributes", NULL }, + { "nul-filenames-only", 0, 0, G_OPTION_ARG_NONE, &opt_nul_filenames_only, "Print only filenames, NUL separated", NULL }, + { NULL } +}; + +static void +print_one_file_text (GFile *f, + GFileInfo *file_info) +{ + g_autoptr(GString) buf = g_string_new (""); + char type_c; + guint32 mode; + guint32 type; + + if (!ostree_repo_file_ensure_resolved ((OstreeRepoFile*)f, NULL)) + g_assert_not_reached (); + + type_c = '?'; + mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); + type = g_file_info_get_file_type (file_info); + switch (type) + { + case G_FILE_TYPE_REGULAR: + type_c = '-'; + break; + case G_FILE_TYPE_DIRECTORY: + type_c = 'd'; + break; + case G_FILE_TYPE_SYMBOLIC_LINK: + type_c = 'l'; + break; + case G_FILE_TYPE_SPECIAL: + if (S_ISCHR(mode)) + type_c = 'c'; + else if (S_ISBLK(mode)) + type_c = 'b'; + break; + case G_FILE_TYPE_UNKNOWN: + case G_FILE_TYPE_SHORTCUT: + case G_FILE_TYPE_MOUNTABLE: + g_assert_not_reached (); + break; + } + g_string_append_c (buf, type_c); + g_string_append_printf (buf, "0%04o %u %u %6" G_GUINT64_FORMAT " ", + mode & ~S_IFMT, + g_file_info_get_attribute_uint32 (file_info, "unix::uid"), + g_file_info_get_attribute_uint32 (file_info, "unix::gid"), + g_file_info_get_attribute_uint64 (file_info, "standard::size")); + + if (opt_checksum) + { + if (type == G_FILE_TYPE_DIRECTORY) + g_string_append_printf (buf, "%s ", ostree_repo_file_tree_get_contents_checksum ((OstreeRepoFile*)f)); + g_string_append_printf (buf, "%s ", ostree_repo_file_get_checksum ((OstreeRepoFile*)f)); + } + + if (opt_xattrs) + { + GVariant *xattrs; + char *formatted; + + if (!ostree_repo_file_get_xattrs ((OstreeRepoFile*)f, &xattrs, NULL, NULL)) + g_assert_not_reached (); + + formatted = g_variant_print (xattrs, TRUE); + g_string_append (buf, "{ "); + g_string_append (buf, formatted); + g_string_append (buf, " } "); + g_free (formatted); + g_variant_unref (xattrs); + } + + g_string_append (buf, gs_file_get_path_cached (f)); + + if (type == G_FILE_TYPE_SYMBOLIC_LINK) + g_string_append_printf (buf, " -> %s", g_file_info_get_attribute_byte_string (file_info, "standard::symlink-target")); + + g_print ("%s\n", buf->str); +} + +static void +print_one_file_binary (GFile *f, + GFileInfo *file_info) +{ + const char *path; + + if (!ostree_repo_file_ensure_resolved ((OstreeRepoFile*)f, NULL)) + g_assert_not_reached (); + + path = gs_file_get_path_cached (f); + + fwrite (path, 1, strlen (path), stdout); + fwrite ("\0", 1, 1, stdout); +} + +static void +print_one_file (GFile *f, + GFileInfo *file_info) +{ + if (opt_nul_filenames_only) + print_one_file_binary (f, file_info); + else + print_one_file_text (f, file_info); +} + +static gboolean +print_directory_recurse (GFile *f, + int depth, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GFileEnumerator) dir_enum = NULL; + g_autoptr(GFile) child = NULL; + g_autoptr(GFileInfo) child_info = NULL; + GError *temp_error = NULL; + + if (depth > 0) + depth--; + else if (depth == 0) + return TRUE; + else + g_assert (depth == -1); + + dir_enum = g_file_enumerate_children (f, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, + error); + if (!dir_enum) + goto out; + + while ((child_info = g_file_enumerator_next_file (dir_enum, NULL, &temp_error)) != NULL) + { + g_clear_object (&child); + child = g_file_get_child (f, g_file_info_get_name (child_info)); + + print_one_file (child, child_info); + + if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY) + { + if (!print_directory_recurse (child, depth, error)) + goto out; + } + + g_clear_object (&child_info); + } + if (temp_error) + { + g_propagate_error (error, temp_error); + goto out; + } + + ret = TRUE; + out: + return ret; +} + +static gboolean +print_one_argument (OstreeRepo *repo, + GFile *root, + const char *arg, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GFile) f = NULL; + g_autoptr(GFileInfo) file_info = NULL; + + f = g_file_resolve_relative_path (root, arg); + + file_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!file_info) + goto out; + + print_one_file (f, file_info); + + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) + { + if (opt_recursive) + { + if (!print_directory_recurse (f, -1, error)) + goto out; + } + else if (!opt_dironly) + { + if (!print_directory_recurse (f, 1, error)) + goto out; + } + } + + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_builtin_ls (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + gboolean ret = FALSE; + const char *rev; + int i; + g_autoptr(GFile) root = NULL; + + context = g_option_context_new ("COMMIT [PATH...]"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (argc <= 1) + { + ot_util_usage_error (context, "An COMMIT argument is required", error); + goto out; + } + rev = argv[1]; + + if (!ostree_repo_read_commit (repo, rev, &root, NULL, cancellable, error)) + goto out; + + if (argc > 2) + { + for (i = 2; i < argc; i++) + { + if (!print_one_argument (repo, root, argv[i], cancellable, error)) + goto out; + } + } + else + { + if (!print_one_argument (repo, root, "/", cancellable, error)) + goto out; + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-builtin-prune.c b/src/ostree/ot-builtin-prune.c new file mode 100644 index 0000000..fd2ab05 --- /dev/null +++ b/src/ostree/ot-builtin-prune.c @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" +#include "parse-datetime.h" + +static gboolean opt_no_prune; +static gboolean opt_static_deltas_only; +static gint opt_depth = -1; +static gboolean opt_refs_only; +static char *opt_delete_commit; +static char *opt_keep_younger_than; +static char **opt_retain_branch_depth; +static char **opt_only_branches; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-prune.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "no-prune", 0, 0, G_OPTION_ARG_NONE, &opt_no_prune, "Only display unreachable objects; don't delete", NULL }, + { "refs-only", 0, 0, G_OPTION_ARG_NONE, &opt_refs_only, "Only compute reachability via refs", NULL }, + { "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Only traverse DEPTH parents for each commit (default: -1=infinite)", "DEPTH" }, + { "delete-commit", 0, 0, G_OPTION_ARG_STRING, &opt_delete_commit, "Specify a commit to delete", "COMMIT" }, + { "keep-younger-than", 0, 0, G_OPTION_ARG_STRING, &opt_keep_younger_than, "Prune all commits older than the specified date", "DATE" }, + { "static-deltas-only", 0, 0, G_OPTION_ARG_NONE, &opt_static_deltas_only, "Change the behavior of delete-commit and keep-younger-than to prune only static deltas" }, + { "retain-branch-depth", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_retain_branch_depth, "Additionally retain BRANCH=DEPTH commits", "BRANCH=DEPTH" }, + { "only-branch", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_only_branches, "Only prune BRANCH (may be specified multiple times)", "BRANCH" }, + { NULL } +}; + +static gboolean +delete_commit (OstreeRepo *repo, const char *commit_to_delete, GCancellable *cancellable, GError **error) +{ + g_autoptr(GHashTable) refs = NULL; /* (element-type utf8 utf8) */ + g_autoptr(GHashTable) collection_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + + /* Check refs which are not in a collection. */ + if (!ostree_repo_list_refs (repo, NULL, &refs, cancellable, error)) + return FALSE; + + GLNX_HASH_TABLE_FOREACH_KV(refs, const char *, ref, const char *, commit) + { + if (g_strcmp0 (commit_to_delete, commit) == 0) + return glnx_throw (error, "Commit '%s' is referenced by '%s'", commit_to_delete, ref); + } + + /* And check refs which *are* in a collection. */ + if (!ostree_repo_list_collection_refs (repo, NULL, &collection_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, + cancellable, error)) + return FALSE; + + GLNX_HASH_TABLE_FOREACH_KV (collection_refs, const OstreeCollectionRef*, ref, + const char *, commit) + { + if (g_strcmp0 (commit_to_delete, commit) == 0) + return glnx_throw (error, "Commit '%s' is referenced by (%s, %s)", + commit_to_delete, ref->collection_id, ref->ref_name); + } + + if (!ot_enable_tombstone_commits (repo, error)) + return FALSE; + + if (!ostree_repo_delete_object (repo, OSTREE_OBJECT_TYPE_COMMIT, commit_to_delete, cancellable, error)) + return FALSE; + + return TRUE; +} + +static gboolean +traverse_keep_younger_than (OstreeRepo *repo, const char *checksum, + struct timespec *ts, + GHashTable *reachable, + GCancellable *cancellable, GError **error) +{ + g_autofree char *next_checksum = g_strdup (checksum); + + /* This is the first commit in our loop, which has a ref pointing to it. We + * don't want to auto-prune it. + */ + if (!ostree_repo_traverse_commit_union (repo, checksum, 0, reachable, + cancellable, error)) + return FALSE; + + while (TRUE) + { + g_autoptr(GVariant) commit = NULL; + if (!ostree_repo_load_variant_if_exists (repo, OSTREE_OBJECT_TYPE_COMMIT, next_checksum, + &commit, error)) + return FALSE; + if (!commit) + break; /* This commit was pruned, so we're done */ + + guint64 commit_timestamp = ostree_commit_get_timestamp (commit); + /* Is this commit newer than our --keep-younger-than spec? */ + if (commit_timestamp >= ts->tv_sec) + { + /* It's newer, traverse it */ + if (!ostree_repo_traverse_commit_union (repo, next_checksum, 0, reachable, + cancellable, error)) + return FALSE; + + g_free (next_checksum); + next_checksum = ostree_commit_get_parent (commit); + if (next_checksum) + g_clear_pointer (&commit, (GDestroyNotify)g_variant_unref); + else + break; /* No parent, we're done */ + } + else + break; /* It's older than our spec, we're done */ + } + + return TRUE; +} + +gboolean +ostree_builtin_prune (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new (""); + g_autoptr(OstreeRepo) repo = NULL; + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (!opt_no_prune && !ostree_ensure_repo_writable (repo, error)) + return FALSE; + + /* Special handling for explicit commit deletion here - we do this + * first. + */ + if (opt_delete_commit) + { + if (opt_no_prune) + { + ot_util_usage_error (context, "Cannot specify both --delete-commit and --no-prune", error); + return FALSE; + } + if (opt_static_deltas_only) + { + if(!ostree_repo_prune_static_deltas (repo, opt_delete_commit, cancellable, error)) + return FALSE; + } + else if (!delete_commit (repo, opt_delete_commit, cancellable, error)) + return FALSE; + } + else + { + /* In the future we should make this useful, but for now let's + * error out since what we were doing before was very misleading. + * https://github.com/ostreedev/ostree/issues/1479 + */ + if (opt_static_deltas_only) + return glnx_throw (error, "--static-deltas-only requires --delete-commit; see https://github.com/ostreedev/ostree/issues/1479"); + } + + OstreeRepoPruneFlags pruneflags = 0; + if (opt_refs_only) + pruneflags |= OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY; + if (opt_no_prune) + pruneflags |= OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE; + + /* If no newer more complex options are specified, drop down to the original + * prune API - both to avoid code duplication, and to keep it run from the + * test suite. + */ + gint n_objects_total; + gint n_objects_pruned; + guint64 objsize_total; + if (!(opt_retain_branch_depth || opt_keep_younger_than || opt_only_branches)) + { + if (!ostree_repo_prune (repo, pruneflags, opt_depth, + &n_objects_total, &n_objects_pruned, &objsize_total, + cancellable, error)) + return FALSE; + } + else + { + g_autoptr(GHashTable) all_refs = NULL; + g_autoptr(GHashTable) reachable = ostree_repo_traverse_new_reachable (); + g_autoptr(GHashTable) retain_branch_depth = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + struct timespec keep_younger_than_ts = {0, }; + GHashTableIter hash_iter; + gpointer key, value; + + /* Otherwise, the default is --refs-only; we set this just as a note */ + opt_refs_only = TRUE; + + if (opt_keep_younger_than) + { + if (!parse_datetime (&keep_younger_than_ts, opt_keep_younger_than, NULL)) + return glnx_throw (error, "Could not parse '%s'", opt_keep_younger_than); + } + + /* Process --retain-branch-depth */ + for (char **iter = opt_retain_branch_depth; iter && *iter; iter++) + { + /* bd should look like BRANCH=DEPTH where DEPTH is an int */ + const char *bd = *iter; + const char *eq = strchr (bd, '='); + if (!eq) + return glnx_throw (error, "Invalid value %s, must specify BRANCH=DEPTH", bd); + + const char *depthstr = eq + 1; + errno = EPERM; + char *endptr; + gint64 depth = g_ascii_strtoll (depthstr, &endptr, 10); + if (depth == 0) + { + if (errno == EINVAL) + return glnx_throw (error, "Out of range depth %s", depthstr); + else if (endptr == depthstr) + return glnx_throw (error, "Invalid depth %s", depthstr); + } + g_hash_table_insert (retain_branch_depth, g_strndup (bd, eq - bd), + GINT_TO_POINTER ((int)depth)); + } + + /* We start from the refs */ + /* FIXME: Do we also want to look at ostree_repo_list_collection_refs()? */ + if (!ostree_repo_list_refs (repo, NULL, &all_refs, + cancellable, error)) + return FALSE; + + /* Process --only-branch. Note this combines with --retain-branch-depth; one + * could do e.g.: + * * --only-branch exampleos/x86_64/foo + * * --only-branch exampleos/x86_64/bar + * * --retain-branch-depth exampleos/x86_64/foo=0 + * * --depth 5 + * to prune exampleos/x86_64/foo to just the latest commit, and + * exampleos/x86_64/bar to a depth of 5. + */ + if (opt_only_branches) + { + /* Turn --only-branch into a set */ + g_autoptr(GHashTable) only_branches_set = g_hash_table_new (g_str_hash, g_str_equal); + for (char **iter = opt_only_branches; iter && *iter; iter++) + { + const char *ref = *iter; + /* Ensure the specified branch exists */ + if (!ostree_repo_resolve_rev (repo, ref, FALSE, NULL, error)) + return FALSE; + g_hash_table_add (only_branches_set, (char*)ref); + } + + /* Iterate over all refs, add equivalent of --retain-branch-depth=$ref=-1 + * if the ref isn't in --only-branch set and there wasn't already a + * --retain-branch-depth specified for it. + */ + GLNX_HASH_TABLE_FOREACH (all_refs, const char *, ref) + { + if (!g_hash_table_contains (only_branches_set, ref) && + !g_hash_table_contains (retain_branch_depth, ref)) + { + g_hash_table_insert (retain_branch_depth, g_strdup (ref), GINT_TO_POINTER ((int)-1)); + } + } + } + + /* Traverse each ref, and gather all objects pointed to by it up to a + * specific depth (if configured). + */ + g_hash_table_iter_init (&hash_iter, all_refs); + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + const char *checksum = value; + gpointer depthp = g_hash_table_lookup (retain_branch_depth, key); + gint depth; + + /* Here, we handle a spec like + * --retain-branch-depth=myos/x86_64/stable=-1 + * --retain-branch-depth=myos/x86_64/dev=5 + */ + if (depthp) + depth = GPOINTER_TO_INT(depthp); + else if (opt_keep_younger_than) + { + if (!traverse_keep_younger_than (repo, checksum, + &keep_younger_than_ts, + reachable, + cancellable, error)) + return FALSE; + + /* Okay, we handled the younger-than case; the other + * two fall through to plain depth-based handling below. + */ + continue; /* Note again, we're skipping the below bit */ + } + else + depth = opt_depth; /* No --retain-branch-depth for this branch, use + the global default */ + + g_debug ("Finding objects to keep for commit %s", checksum); + if (!ostree_repo_traverse_commit_union (repo, checksum, depth, reachable, + cancellable, error)) + return FALSE; + } + + /* We've gathered the reachable set; start the prune ✀ */ + { OstreeRepoPruneOptions opts = { pruneflags, reachable }; + if (!ostree_repo_prune_from_reachable (repo, &opts, + &n_objects_total, + &n_objects_pruned, + &objsize_total, + cancellable, error)) + return FALSE; + } + } + + g_autofree char *formatted_freed_size = g_format_size_full (objsize_total, 0); + g_print ("Total objects: %u\n", n_objects_total); + if (n_objects_pruned == 0) + g_print ("No unreachable objects\n"); + else if (pruneflags & OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE) + g_print ("Would delete: %u objects, freeing %s\n", + n_objects_pruned, formatted_freed_size); + else + g_print ("Deleted %u objects, %s freed\n", + n_objects_pruned, formatted_freed_size); + + return TRUE; +} diff --git a/src/ostree/ot-builtin-pull-local.c b/src/ostree/ot-builtin-pull-local.c new file mode 100644 index 0000000..43f4f25 --- /dev/null +++ b/src/ostree/ot-builtin-pull-local.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +static char *opt_remote; +static gboolean opt_commit_only; +static gboolean opt_disable_fsync; +static gboolean opt_per_object_fsync; +static gboolean opt_untrusted; +static gboolean opt_bareuseronly_files; +static gboolean opt_require_static_deltas; +static gboolean opt_gpg_verify; +static gboolean opt_gpg_verify_summary; +static int opt_depth = 0; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-pull-local.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "commit-metadata-only", 0, 0, G_OPTION_ARG_NONE, &opt_commit_only, "Fetch only the commit metadata", NULL }, + { "remote", 0, 0, G_OPTION_ARG_STRING, &opt_remote, "Add REMOTE to refspec", "REMOTE" }, + { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, + { "per-object-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_per_object_fsync, "Perform writes in such a way that avoids stalling concurrent processes", NULL }, + { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Verify checksums of local sources (always enabled for HTTP pulls)", NULL }, + { "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL }, + { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, + { "gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify, "GPG verify commits (must specify --remote)", NULL }, + { "gpg-verify-summary", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify_summary, "GPG verify summary (must specify --remote)", NULL }, + { "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" }, + { NULL } +}; + +/* See canonical version of this in ot-builtin-pull.c */ +static void +noninteractive_console_progress_changed (OstreeAsyncProgress *progress, + gpointer user_data) +{ + /* We do nothing here - we just want the final status */ +} + +gboolean +ostree_builtin_pull_local (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + int i; + const char *src_repo_arg; + g_autofree char *src_repo_uri = NULL; + g_autoptr(OstreeAsyncProgress) progress = NULL; + g_autoptr(GPtrArray) refs_to_fetch = NULL; + OstreeRepoPullFlags pullflags = 0; + + context = g_option_context_new ("SRC_REPO [REFS...]"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (!ostree_ensure_repo_writable (repo, error)) + goto out; + + if (argc < 2) + { + gchar *help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s\n", help); + g_free (help); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "DESTINATION must be specified"); + goto out; + } + + src_repo_arg = argv[1]; + + if (src_repo_arg[0] == '/') + src_repo_uri = g_strconcat ("file://", src_repo_arg, NULL); + else + { + g_autofree char *cwd = g_get_current_dir (); + src_repo_uri = g_strconcat ("file://", cwd, "/", src_repo_arg, NULL); + } + + if (opt_untrusted) + pullflags |= OSTREE_REPO_PULL_FLAGS_UNTRUSTED; + if (opt_bareuseronly_files) + pullflags |= OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES; + if (opt_commit_only) + pullflags |= OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY; + + if (opt_disable_fsync) + ostree_repo_set_disable_fsync (repo, TRUE); + + if (argc == 2) + { + g_autoptr(GFile) src_repo_path = g_file_new_for_path (src_repo_arg); + g_autoptr(OstreeRepo) src_repo = ostree_repo_new (src_repo_path); + g_autoptr(GHashTable) refs_to_clone = NULL; + + refs_to_fetch = g_ptr_array_new_with_free_func (g_free); + + if (!ostree_repo_open (src_repo, cancellable, error)) + goto out; + + /* FIXME: This should grow support for pulling refs from refs/mirrors on + * a local repository, using ostree_repo_list_collection_refs(). */ + if (!ostree_repo_list_refs (src_repo, NULL, &refs_to_clone, + cancellable, error)) + goto out; + + { GHashTableIter hashiter; + gpointer hkey, hvalue; + + g_hash_table_iter_init (&hashiter, refs_to_clone); + while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue)) + g_ptr_array_add (refs_to_fetch, g_strdup (hkey)); + } + g_ptr_array_add (refs_to_fetch, NULL); + } + else + { + refs_to_fetch = g_ptr_array_new (); + for (i = 2; i < argc; i++) + { + const char *ref = argv[i]; + + g_ptr_array_add (refs_to_fetch, (char*)ref); + } + g_ptr_array_add (refs_to_fetch, NULL); + } + + { GVariantBuilder builder; + g_autoptr(GVariant) opts = NULL; + g_auto(GLnxConsoleRef) console = { 0, }; + + glnx_console_lock (&console); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + g_variant_builder_add (&builder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (pullflags))); + g_variant_builder_add (&builder, "{s@v}", "refs", + g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch->pdata, -1))); + if (opt_remote) + g_variant_builder_add (&builder, "{s@v}", "override-remote-name", + g_variant_new_variant (g_variant_new_string (opt_remote))); + g_variant_builder_add (&builder, "{s@v}", "require-static-deltas", + g_variant_new_variant (g_variant_new_boolean (opt_require_static_deltas))); + if (opt_gpg_verify) + g_variant_builder_add (&builder, "{s@v}", "gpg-verify", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + if (opt_gpg_verify_summary) + g_variant_builder_add (&builder, "{s@v}", "gpg-verify-summary", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + g_variant_builder_add (&builder, "{s@v}", "depth", + g_variant_new_variant (g_variant_new_int32 (opt_depth))); + /* local pulls always disable signapi verification. If you don't want this, use + * ostree remote add --sign-verify= file:// + */ + g_variant_builder_add (&builder, "{s@v}", "disable-sign-verify", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + g_variant_builder_add (&builder, "{s@v}", "disable-sign-verify-summary", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + if (opt_per_object_fsync) + g_variant_builder_add (&builder, "{s@v}", "per-object-fsync", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + + if (console.is_tty) + progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); + else + progress = ostree_async_progress_new_and_connect (noninteractive_console_progress_changed, &console); + + opts = g_variant_ref_sink (g_variant_builder_end (&builder)); + if (!ostree_repo_pull_with_options (repo, src_repo_uri, + opts, + progress, + cancellable, error)) + goto out; + + if (!console.is_tty) + { + g_assert (progress); + const char *status = ostree_async_progress_get_status (progress); + if (status) + g_print ("%s\n", status); + } + ostree_async_progress_finish (progress); + } + + ret = TRUE; + out: + if (repo) + ostree_repo_abort_transaction (repo, cancellable, NULL); + return ret; +} diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c new file mode 100644 index 0000000..e69d62e --- /dev/null +++ b/src/ostree/ot-builtin-pull.c @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +static gboolean opt_disable_fsync; +static gboolean opt_per_object_fsync; +static gboolean opt_mirror; +static gboolean opt_commit_only; +static gboolean opt_dry_run; +static gboolean opt_disable_static_deltas; +static gboolean opt_require_static_deltas; +static gboolean opt_untrusted; +static gboolean opt_http_trusted; +static gboolean opt_timestamp_check; +static char* opt_timestamp_check_from_rev; +static gboolean opt_bareuseronly_files; +static char** opt_subpaths; +static char** opt_http_headers; +static char* opt_cache_dir; +static char* opt_append_user_agent; +static int opt_depth = 0; +static int opt_frequency = 0; +static int opt_network_retries = -1; +static char* opt_url; +static char** opt_localcache_repos; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-pull.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "commit-metadata-only", 0, 0, G_OPTION_ARG_NONE, &opt_commit_only, "Fetch only the commit metadata", NULL }, + { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, + { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, + { "per-object-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_per_object_fsync, "Perform writes in such a way that avoids stalling concurrent processes", NULL }, + { "disable-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_disable_static_deltas, "Do not use static deltas", NULL }, + { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, + { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror and fetches all refs if none provided", NULL }, + { "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL }, + { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Verify checksums of local sources (always enabled for HTTP pulls)", NULL }, + { "http-trusted", 0, 0, G_OPTION_ARG_NONE, &opt_http_trusted, "Do not verify checksums of HTTP sources (mostly useful when mirroring)", NULL }, + { "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL }, + { "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL }, + { "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" }, + { "url", 0, 0, G_OPTION_ARG_STRING, &opt_url, "Pull objects from this URL instead of the one from the remote config", "URL" }, + { "http-header", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_http_headers, "Add NAME=VALUE as HTTP header to all requests", "NAME=VALUE" }, + { "update-frequency", 0, 0, G_OPTION_ARG_INT, &opt_frequency, "Sets the update frequency, in milliseconds (0=1000ms) (default: 0)", "FREQUENCY" }, + { "network-retries", 0, 0, G_OPTION_ARG_INT, &opt_network_retries, "Specifies how many times each download should be retried upon error (default: 5)", "N"}, + { "localcache-repo", 'L', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_localcache_repos, "Add REPO as local cache source for objects during this pull", "REPO" }, + { "timestamp-check", 'T', 0, G_OPTION_ARG_NONE, &opt_timestamp_check, "Require fetched commits to have newer timestamps", NULL }, + { "timestamp-check-from-rev", 0, 0, G_OPTION_ARG_STRING, &opt_timestamp_check_from_rev, "Require fetched commits to have newer timestamps than given rev", NULL }, + /* let's leave this hidden for now; we just need it for tests */ + { "append-user-agent", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &opt_append_user_agent, "Append string to user agent", NULL }, + { NULL } + }; + +#ifndef OSTREE_DISABLE_GPGME +static void +gpg_verify_result_cb (OstreeRepo *repo, + const char *checksum, + OstreeGpgVerifyResult *result, + GLnxConsoleRef *console) +{ + /* Temporarily place the tty back in normal mode before printing GPG + * verification results. + */ + glnx_console_unlock (console); + + g_print ("\n"); + ostree_print_gpg_verify_result (result); + + glnx_console_lock (console); +} +#endif /* OSTREE_DISABLE_GPGME */ + +static gboolean printed_console_progress; + +static void +dry_run_console_progress_changed (OstreeAsyncProgress *progress, + gpointer user_data) +{ + guint fetched_delta_parts, total_delta_parts; + guint fetched_delta_part_fallbacks, total_delta_part_fallbacks; + guint64 fetched_delta_part_size, total_delta_part_size, total_delta_part_usize; + + g_assert (!printed_console_progress); + printed_console_progress = TRUE; + + ostree_async_progress_get (progress, + /* Number of parts */ + "fetched-delta-parts", "u", &fetched_delta_parts, + "total-delta-parts", "u", &total_delta_parts, + "fetched-delta-fallbacks", "u", &fetched_delta_part_fallbacks, + "total-delta-fallbacks", "u", &total_delta_part_fallbacks, + /* Size variables */ + "fetched-delta-part-size", "t", &fetched_delta_part_size, + "total-delta-part-size", "t", &total_delta_part_size, + "total-delta-part-usize", "t", &total_delta_part_usize, + NULL); + + /* Fold the count of deltaparts + fallbacks for simplicity; if changing this, + * please change ostree_repo_pull_default_console_progress_changed() first. + */ + fetched_delta_parts += fetched_delta_part_fallbacks; + total_delta_parts += total_delta_part_fallbacks; + + g_autoptr(GString) buf = g_string_new (""); + + { g_autofree char *formatted_fetched = + g_format_size (fetched_delta_part_size); + g_autofree char *formatted_size = + g_format_size (total_delta_part_size); + g_autofree char *formatted_usize = + g_format_size (total_delta_part_usize); + + g_string_append_printf (buf, "Delta update: %u/%u parts, %s/%s, %s total uncompressed", + fetched_delta_parts, total_delta_parts, + formatted_fetched, formatted_size, + formatted_usize); + } + g_print ("%s\n", buf->str); +} + +static void +noninteractive_console_progress_changed (OstreeAsyncProgress *progress, + gpointer user_data) +{ + /* We do nothing here - we just want the final status */ +} + +gboolean +ostree_builtin_pull (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + gboolean ret = FALSE; + g_autofree char *remote = NULL; + OstreeRepoPullFlags pullflags = 0; + g_autoptr(GPtrArray) refs_to_fetch = NULL; + g_autoptr(GPtrArray) override_commit_ids = NULL; + g_autoptr(OstreeAsyncProgress) progress = NULL; + gulong signal_handler_id = 0; + + context = g_option_context_new ("REMOTE [BRANCH...]"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (!ostree_ensure_repo_writable (repo, error)) + goto out; + + if (argc < 2) + { + ot_util_usage_error (context, "REMOTE must be specified", error); + goto out; + } + + if (opt_disable_fsync) + ostree_repo_set_disable_fsync (repo, TRUE); + + if (opt_cache_dir) + { + if (!ostree_repo_set_cache_dir (repo, AT_FDCWD, opt_cache_dir, cancellable, error)) + goto out; + } + + if (opt_mirror) + pullflags |= OSTREE_REPO_PULL_FLAGS_MIRROR; + + if (opt_commit_only) + pullflags |= OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY; + + if (opt_http_trusted) + pullflags |= OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP; + if (opt_untrusted) + { + pullflags |= OSTREE_REPO_PULL_FLAGS_UNTRUSTED; + /* If the user specifies both, assume they really mean untrusted */ + pullflags &= ~OSTREE_REPO_PULL_FLAGS_TRUSTED_HTTP; + } + if (opt_bareuseronly_files) + pullflags |= OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES; + + if (opt_dry_run && !opt_require_static_deltas) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "--dry-run requires --require-static-deltas"); + goto out; + } + + if (strchr (argv[1], ':') == NULL) + { + remote = g_strdup (argv[1]); + if (argc > 2) + { + int i; + refs_to_fetch = g_ptr_array_new_with_free_func (g_free); + + for (i = 2; i < argc; i++) + { + const char *at = strrchr (argv[i], '@'); + + if (at) + { + guint j; + const char *override_commit_id = at + 1; + + if (!ostree_validate_checksum_string (override_commit_id, error)) + goto out; + + if (!override_commit_ids) + { + override_commit_ids = g_ptr_array_new_with_free_func (g_free); + + /* Backfill */ + for (j = 2; j < i; j++) + g_ptr_array_add (override_commit_ids, g_strdup ("")); + } + + g_ptr_array_add (override_commit_ids, g_strdup (override_commit_id)); + g_ptr_array_add (refs_to_fetch, g_strndup (argv[i], at - argv[i])); + } + else + { + g_ptr_array_add (refs_to_fetch, g_strdup (argv[i])); + if (override_commit_ids) + g_ptr_array_add (override_commit_ids, g_strdup ("")); + } + } + + g_ptr_array_add (refs_to_fetch, NULL); + } + } + else + { + char *ref_to_fetch; + refs_to_fetch = g_ptr_array_new_with_free_func (g_free); + if (!ostree_parse_refspec (argv[1], &remote, &ref_to_fetch, error)) + goto out; + /* Transfer ownership */ + g_ptr_array_add (refs_to_fetch, ref_to_fetch); + g_ptr_array_add (refs_to_fetch, NULL); + } + + { + GVariantBuilder builder; + g_autoptr(GVariant) options = NULL; + g_auto(GLnxConsoleRef) console = { 0, }; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + glnx_console_lock (&console); + + if (opt_url) + g_variant_builder_add (&builder, "{s@v}", "override-url", + g_variant_new_variant (g_variant_new_string (opt_url))); + if (opt_subpaths && opt_subpaths[0] != NULL) + { + /* Special case the one-element case so that we excercise this + old single-argument version in the tests */ + if (opt_subpaths[1] == NULL) + g_variant_builder_add (&builder, "{s@v}", "subdir", + g_variant_new_variant (g_variant_new_string (opt_subpaths[0]))); + else + g_variant_builder_add (&builder, "{s@v}", "subdirs", + g_variant_new_variant (g_variant_new_strv ((const char *const*) opt_subpaths, -1))); + } + g_variant_builder_add (&builder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (pullflags))); + if (refs_to_fetch) + g_variant_builder_add (&builder, "{s@v}", "refs", + g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch->pdata, -1))); + g_variant_builder_add (&builder, "{s@v}", "depth", + g_variant_new_variant (g_variant_new_int32 (opt_depth))); + + g_variant_builder_add (&builder, "{s@v}", "update-frequency", + g_variant_new_variant (g_variant_new_uint32 (opt_frequency))); + + if (opt_network_retries >= 0) + g_variant_builder_add (&builder, "{s@v}", "n-network-retries", + g_variant_new_variant (g_variant_new_uint32 (opt_network_retries))); + + g_variant_builder_add (&builder, "{s@v}", "disable-static-deltas", + g_variant_new_variant (g_variant_new_boolean (opt_disable_static_deltas))); + + g_variant_builder_add (&builder, "{s@v}", "require-static-deltas", + g_variant_new_variant (g_variant_new_boolean (opt_require_static_deltas))); + + g_variant_builder_add (&builder, "{s@v}", "dry-run", + g_variant_new_variant (g_variant_new_boolean (opt_dry_run))); + if (opt_timestamp_check) + g_variant_builder_add (&builder, "{s@v}", "timestamp-check", + g_variant_new_variant (g_variant_new_boolean (opt_timestamp_check))); + if (opt_timestamp_check_from_rev) + g_variant_builder_add (&builder, "{s@v}", "timestamp-check-from-rev", + g_variant_new_variant (g_variant_new_string (opt_timestamp_check_from_rev))); + + if (override_commit_ids) + g_variant_builder_add (&builder, "{s@v}", "override-commit-ids", + g_variant_new_variant (g_variant_new_strv ((const char*const*)override_commit_ids->pdata, override_commit_ids->len))); + if (opt_localcache_repos) + g_variant_builder_add (&builder, "{s@v}", "localcache-repos", + g_variant_new_variant (g_variant_new_strv ((const char*const*)opt_localcache_repos, -1))); + if (opt_per_object_fsync) + g_variant_builder_add (&builder, "{s@v}", "per-object-fsync", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + if (opt_http_headers) + { + GVariantBuilder hdr_builder; + g_variant_builder_init (&hdr_builder, G_VARIANT_TYPE ("a(ss)")); + + for (char **iter = opt_http_headers; iter && *iter; iter++) + { + const char *kv = *iter; + const char *eq = strchr (kv, '='); + g_autofree char *key = NULL; + if (!eq) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing '=' in --http-header"); + goto out; + } + key = g_strndup (kv, eq - kv); + g_variant_builder_add (&hdr_builder, "(ss)", key, eq + 1); + } + g_variant_builder_add (&builder, "{s@v}", "http-headers", + g_variant_new_variant (g_variant_builder_end (&hdr_builder))); + } + + if (opt_append_user_agent) + g_variant_builder_add (&builder, "{s@v}", "append-user-agent", + g_variant_new_variant (g_variant_new_string (opt_append_user_agent))); + + if (!opt_dry_run) + { + if (console.is_tty) + progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); + else + progress = ostree_async_progress_new_and_connect (noninteractive_console_progress_changed, &console); + } + else + { + progress = ostree_async_progress_new_and_connect (dry_run_console_progress_changed, NULL); + } + + if (console.is_tty) + { +#ifndef OSTREE_DISABLE_GPGME + signal_handler_id = g_signal_connect (repo, "gpg-verify-result", + G_CALLBACK (gpg_verify_result_cb), + &console); +#endif /* OSTREE_DISABLE_GPGME */ + } + + options = g_variant_ref_sink (g_variant_builder_end (&builder)); + + if (!ostree_repo_pull_with_options (repo, remote, options, + progress, cancellable, error)) + goto out; + + if (!console.is_tty && !opt_dry_run) + { + g_assert (progress); + const char *status = ostree_async_progress_get_status (progress); + if (status) + g_print ("%s\n", status); + } + + ostree_async_progress_finish (progress); + + if (opt_dry_run) + g_assert (printed_console_progress); + } + + ret = TRUE; + out: + if (signal_handler_id > 0) + g_signal_handler_disconnect (repo, signal_handler_id); + return ret; +} diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c new file mode 100644 index 0000000..1e0b101 --- /dev/null +++ b/src/ostree/ot-builtin-refs.c @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" + +static gboolean opt_delete; +static gboolean opt_list; +static gboolean opt_alias; +static char *opt_create; +static gboolean opt_collections; +static gboolean opt_force; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-refs.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "delete", 0, 0, G_OPTION_ARG_NONE, &opt_delete, "Delete refs which match PREFIX, rather than listing them", NULL }, + { "list", 0, 0, G_OPTION_ARG_NONE, &opt_list, "Do not remove the prefix from the refs", NULL }, + { "alias", 'A', 0, G_OPTION_ARG_NONE, &opt_alias, "If used with --create, create an alias, otherwise just list aliases", NULL }, + { "create", 0, 0, G_OPTION_ARG_STRING, &opt_create, "Create a new ref for an existing commit", "NEWREF" }, + { "collections", 'c', 0, G_OPTION_ARG_NONE, &opt_collections, "Enable listing collection IDs for refs", NULL }, + { "force", 0, 0, G_OPTION_ARG_NONE, &opt_force, "Overwrite existing refs when creating", NULL }, + { NULL } +}; + +static gboolean +do_ref_with_collections (OstreeRepo *repo, + const char *refspec_prefix, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GHashTable) refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + GHashTableIter hashiter; + gpointer hashkey, hashvalue; + gboolean ret = FALSE; + + if (!ostree_repo_list_collection_refs (repo, + (!opt_create) ? refspec_prefix : NULL, + &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, + cancellable, error)) + goto out; + + if (!opt_delete && !opt_create) + { + g_hash_table_iter_init (&hashiter, refs); + while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + { + const OstreeCollectionRef *ref = hashkey; + g_print ("(%s, %s)\n", ref->collection_id, ref->ref_name); + } + } + else if (opt_create) + { + g_autofree char *checksum = NULL; + g_autofree char *checksum_existing = NULL; + + if (!ostree_repo_resolve_rev_ext (repo, opt_create, TRUE, OSTREE_REPO_RESOLVE_REV_EXT_NONE, &checksum_existing, error)) + { + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) + { + /* A folder exists with the specified ref name, + * which is handled by _ostree_repo_write_ref */ + g_clear_error (error); + } + else goto out; + } + + if (!opt_force && checksum_existing != NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "--create specified but ref %s already exists", opt_create); + goto out; + } + + if (!ostree_repo_resolve_rev (repo, refspec_prefix, FALSE, &checksum, error)) + goto out; + + /* This is technically an abuse of the refspec syntax: collection IDs + * should not be treated like remote names. */ + g_auto(GStrv) parts = g_strsplit (opt_create, ":", 2); + const char *collection_id = parts[0]; + const char *ref_name = parts[1]; + if (!ostree_validate_collection_id (collection_id, error)) + goto out; + if (!ostree_validate_rev (ref_name, error)) + goto out; + + const OstreeCollectionRef ref = { (gchar *) collection_id, (gchar *) ref_name }; + if (!ostree_repo_set_collection_ref_immediate (repo, &ref, checksum, + cancellable, error)) + goto out; + } + else + /* delete */ + { + g_hash_table_iter_init (&hashiter, refs); + while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + { + const OstreeCollectionRef *ref = hashkey; + + if (!ostree_repo_set_collection_ref_immediate (repo, ref, NULL, + cancellable, error)) + goto out; + } + } + ret = TRUE; + out: + return ret; +} + +static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellable *cancellable, GError **error) +{ + g_autoptr(GHashTable) refs = NULL; + g_autoptr(GHashTable) ref_aliases = NULL; + GHashTableIter hashiter; + gpointer hashkey, hashvalue; + gboolean ret = FALSE; + gboolean is_list; + + if (opt_collections) + return do_ref_with_collections (repo, refspec_prefix, cancellable, error); + + /* If we're doing aliasing, we need the full list of aliases mostly to allow + * replacing existing aliases. + * If we are deleting a ref, we want to make sure that it doesn't have + * any corresponding aliases. + */ + if (opt_alias || opt_delete) + { + if (!ostree_repo_list_refs_ext (repo, NULL, &ref_aliases, + OSTREE_REPO_LIST_REFS_EXT_ALIASES, + cancellable, error)) + goto out; + } + + is_list = !(opt_delete || opt_create); + + if (opt_delete || opt_list || (!opt_create && opt_alias)) + { + OstreeRepoListRefsExtFlags flags = OSTREE_REPO_LIST_REFS_EXT_NONE; + if (opt_alias) + flags |= OSTREE_REPO_LIST_REFS_EXT_ALIASES; + if (!ostree_repo_list_refs_ext (repo, refspec_prefix, &refs, flags, + cancellable, error)) + goto out; + } + else if (opt_create) + { + if (!ostree_repo_list_refs_ext (repo, NULL, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, + cancellable, error)) + goto out; + } + else if (!ostree_repo_list_refs (repo, refspec_prefix, &refs, cancellable, error)) + goto out; + + if (is_list) + { + GLNX_HASH_TABLE_FOREACH_KV (refs, const char *, ref, const char *, value) + { + if (opt_alias) + g_print ("%s -> %s\n", ref, value); + else + g_print ("%s\n", ref); + } + } + else if (opt_create) + { + g_autofree char *checksum = NULL; + g_autofree char *checksum_existing = NULL; + g_autofree char *remote = NULL; + g_autofree char *ref = NULL; + + if (!ostree_repo_resolve_rev_ext (repo, opt_create, TRUE, OSTREE_REPO_RESOLVE_REV_EXT_NONE, &checksum_existing, error)) + { + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) + { + /* A folder exists with the specified ref name, + * which is handled by _ostree_repo_write_ref */ + g_clear_error (error); + } + else goto out; + } + + /* We want to allow replacing an existing alias or a normal ref when + * forced + */ + gboolean replacing_alias = opt_alias && g_hash_table_contains (ref_aliases, opt_create); + if (!replacing_alias && !opt_force && checksum_existing != NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "--create specified but ref %s already exists", opt_create); + goto out; + } + + if (!ostree_parse_refspec (opt_create, &remote, &ref, error)) + goto out; + + if (opt_alias) + { + if (remote) + return glnx_throw (error, "Cannot create alias to remote ref: %s", remote); + if (!g_hash_table_contains (refs, refspec_prefix)) + return glnx_throw (error, "Cannot create alias to non-existent ref: %s", + refspec_prefix); + if (!ostree_repo_set_alias_ref_immediate (repo, remote, ref, refspec_prefix, + cancellable, error)) + goto out; + } + else + { + if (!ostree_repo_resolve_rev (repo, refspec_prefix, FALSE, &checksum, error)) + goto out; + + if (!ostree_repo_set_ref_immediate (repo, remote, ref, checksum, + cancellable, error)) + goto out; + } + } + else + /* delete */ + { + g_hash_table_iter_init (&hashiter, refs); + while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + { + const char *refspec = hashkey; + g_autofree char *remote = NULL; + g_autofree char *ref = NULL; + + if (!ostree_parse_refspec (refspec, &remote, &ref, error)) + goto out; + + /* Look for alias if it exists for a ref we want to delete */ + GLNX_HASH_TABLE_FOREACH_KV (ref_aliases, const char *, + ref_alias, const char *, value) + { + if (!strcmp (ref, value)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Ref '%s' has an active alias: '%s'", ref, ref_alias); + goto out; + } + } + if (!ostree_repo_set_ref_immediate (repo, remote, ref, NULL, + cancellable, error)) + goto out; + } + } + ret = TRUE; + out: + return ret; +} + +gboolean +ostree_builtin_refs (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + int i; + + context = g_option_context_new ("[PREFIX]"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (argc >= 2) + { + if (opt_create && argc > 2) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "You must specify only 1 existing ref when creating a new ref"); + goto out; + } + for (i = 1; i < argc; i++) + if (!do_ref (repo, argv[i], cancellable, error)) + goto out; + } + else + { + /* Require a prefix when deleting to help avoid accidents. */ + if (opt_delete) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "At least one PREFIX is required when deleting refs"); + goto out; + } + else if (opt_create) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "You must specify a revision when creating a new ref"); + goto out; + } + + if (!do_ref (repo, NULL, cancellable, error)) + goto out; + } + + ret = TRUE; + out: + if (repo) + ostree_repo_abort_transaction (repo, cancellable, NULL); + return ret; +} diff --git a/src/ostree/ot-builtin-remote.c b/src/ostree/ot-builtin-remote.c new file mode 100644 index 0000000..6b3f6a2 --- /dev/null +++ b/src/ostree/ot-builtin-remote.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ot-remote-builtins.h" + +static OstreeCommand remote_subcommands[] = { + { "add", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_remote_builtin_add, + "Add a remote repository" }, + { "delete", OSTREE_BUILTIN_FLAG_NO_REPO, + ot_remote_builtin_delete, + "Delete a remote repository" }, + { "show-url", OSTREE_BUILTIN_FLAG_NONE, + ot_remote_builtin_show_url, + "Show remote repository URL" }, + { "list", OSTREE_BUILTIN_FLAG_NONE, + ot_remote_builtin_list, + "List remote repository names" }, +#ifndef OSTREE_DISABLE_GPGME + { "gpg-import", OSTREE_BUILTIN_FLAG_NONE, + ot_remote_builtin_gpg_import, + "Import GPG keys" }, +#endif /* OSTREE_DISABLE_GPGME */ +#ifdef HAVE_LIBCURL_OR_LIBSOUP + { "add-cookie", OSTREE_BUILTIN_FLAG_NONE, + ot_remote_builtin_add_cookie, + "Add a cookie to remote" }, + { "delete-cookie", OSTREE_BUILTIN_FLAG_NONE, + ot_remote_builtin_delete_cookie, + "Remove one cookie from remote" }, + { "list-cookies", OSTREE_BUILTIN_FLAG_NONE, + ot_remote_builtin_list_cookies, + "Show remote repository cookies" }, +#endif + { "refs", OSTREE_BUILTIN_FLAG_NONE, + ot_remote_builtin_refs, + "List remote refs" }, + { "summary", OSTREE_BUILTIN_FLAG_NONE, + ot_remote_builtin_summary, + "Show remote summary" }, + { NULL, 0, NULL, NULL } +}; + +static GOptionContext * +remote_option_context_new_with_commands (void) +{ + OstreeCommand *subcommand = remote_subcommands; + GOptionContext *context = g_option_context_new ("COMMAND"); + + g_autoptr(GString) summary = g_string_new ("Builtin \"remote\" Commands:"); + + while (subcommand->name != NULL) + { + if ((subcommand->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0) + { + g_string_append_printf (summary, "\n %-18s", subcommand->name); + if (subcommand->description != NULL) + g_string_append_printf (summary, "%s", subcommand->description); + } + subcommand++; + } + + g_option_context_set_summary (context, summary->str); + + return context; +} + +gboolean +ostree_builtin_remote (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + const char *subcommand_name = NULL; + int in,out; + for (in = 1, out = 1; in < argc; in++, out++) + { + /* The non-option is the command, take it out of the arguments */ + if (argv[in][0] != '-') + { + if (subcommand_name == NULL) + { + subcommand_name = argv[in]; + out--; + continue; + } + } + + else if (g_str_equal (argv[in], "--")) + { + break; + } + + argv[out] = argv[in]; + } + + argc = out; + + OstreeCommand *subcommand = remote_subcommands; + while (subcommand->name) + { + if (g_strcmp0 (subcommand_name, subcommand->name) == 0) + break; + subcommand++; + } + + if (!subcommand->name) + { + g_autoptr(GOptionContext) context = NULL; + g_autofree char *help = NULL; + + context = remote_option_context_new_with_commands (); + + /* This will not return for some options (e.g. --version). */ + if (ostree_option_context_parse (context, NULL, &argc, &argv, + invocation, NULL, cancellable, + error)) + { + if (subcommand_name == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No \"remote\" subcommand specified"); + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown \"remote\" subcommand '%s'", subcommand_name); + } + } + + help = g_option_context_get_help (context, FALSE, NULL); + g_printerr ("%s", help); + + return FALSE; + } + + g_autofree char *prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name); + g_set_prgname (prgname); + + OstreeCommandInvocation sub_invocation = { .command = subcommand }; + if (!subcommand->fn (argc, argv, &sub_invocation, cancellable, error)) + return FALSE; + + return TRUE; +} diff --git a/src/ostree/ot-builtin-reset.c b/src/ostree/ot-builtin-reset.c new file mode 100644 index 0000000..2e25cb9 --- /dev/null +++ b/src/ostree/ot-builtin-reset.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2013 Stef Walter + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Stef Walter + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-reset.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { NULL } +}; + +gboolean +ostree_builtin_reset (int argc, + char **argv, + OstreeCommandInvocation *invocation, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GHashTable) known_refs = NULL; + gboolean ret = FALSE; + const char *ref; + const char *target = NULL; + g_autofree char *checksum = NULL; + + /* FIXME: Add support for collection–refs. */ + context = g_option_context_new ("REF COMMIT"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (!ostree_ensure_repo_writable (repo, error)) + goto out; + + if (argc <= 2) + { + ot_util_usage_error (context, "A REF and COMMIT argument is required", error); + goto out; + } + ref = argv[1]; + target = argv[2]; + + if (!ostree_repo_list_refs (repo, NULL, &known_refs, cancellable, error)) + goto out; + + if (!g_hash_table_contains (known_refs, ref)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR, "Invalid ref '%s'", ref); + goto out; + } + + if (!ostree_repo_resolve_rev (repo, target, FALSE, &checksum, error)) + goto out; + + if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) + goto out; + + ostree_repo_transaction_set_ref (repo, NULL, ref, checksum); + + if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) + goto out; + + ret = TRUE; + out: + if (repo) + ostree_repo_abort_transaction (repo, cancellable, NULL); + return ret; +} diff --git a/src/ostree/ot-builtin-rev-parse.c b/src/ostree/ot-builtin-rev-parse.c new file mode 100644 index 0000000..0f2c2ce --- /dev/null +++ b/src/ostree/ot-builtin-rev-parse.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-rev-parse.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { NULL } +}; + +gboolean +ostree_builtin_rev_parse (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + gboolean ret = FALSE; + const char *rev = "master"; + int i; + g_autofree char *resolved_rev = NULL; + + context = g_option_context_new ("REV"); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + ot_util_usage_error (context, "REV must be specified", error); + goto out; + } + for (i = 1; i < argc; i++) + { + rev = argv[i]; + g_free (resolved_rev); + resolved_rev = NULL; + if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error)) + goto out; + g_print ("%s\n", resolved_rev); + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-builtin-show.c b/src/ostree/ot-builtin-show.c new file mode 100644 index 0000000..96e2d4c --- /dev/null +++ b/src/ostree/ot-builtin-show.c @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ot-dump.h" +#include "ostree.h" +#include "otutil.h" + +static gboolean opt_print_related; +static char* opt_print_variant_type; +static char* opt_print_metadata_key; +static char* opt_print_detached_metadata_key; +static gboolean opt_print_sizes; +static gboolean opt_raw; +static gboolean opt_no_byteswap; +static char *opt_gpg_homedir; +static char *opt_gpg_verify_remote; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-show.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "print-related", 0, 0, G_OPTION_ARG_NONE, &opt_print_related, "Show the \"related\" commits", NULL }, + { "print-variant-type", 0, 0, G_OPTION_ARG_STRING, &opt_print_variant_type, "Memory map OBJECT (in this case a filename) to the GVariant type string", "TYPE" }, + { "print-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_metadata_key, "Print string value of metadata key", "KEY" }, + { "print-detached-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_detached_metadata_key, "Print string value of detached metadata key", "KEY" }, + { "print-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_print_sizes, "Show the commit size metadata", NULL }, + { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data" }, + { "no-byteswap", 'B', 0, G_OPTION_ARG_NONE, &opt_no_byteswap, "Do not automatically convert variant data from big endian" }, + { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, + { "gpg-verify-remote", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_verify_remote, "Use REMOTE name for GPG configuration", "REMOTE"}, + { NULL } +}; + +static gboolean +do_print_variant_generic (const GVariantType *type, + const char *filename, + GError **error) +{ + g_autoptr(GVariant) variant = NULL; + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (AT_FDCWD, filename, TRUE, &fd, error)) + return FALSE; + if (!ot_variant_read_fd (fd, 0, type, FALSE, &variant, error)) + return FALSE; + + ot_dump_variant (variant); + return TRUE; +} + +static gboolean +do_print_related (OstreeRepo *repo, + const char *rev, + const char *resolved_rev, + GError **error) +{ + g_autoptr(GVariant) variant = NULL; + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + resolved_rev, &variant, error)) + return FALSE; + + /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */ + g_autoptr(GVariant) related = g_variant_get_child_value (variant, 2); + g_autoptr(GVariantIter) viter = g_variant_iter_new (related); + + const char *name; + GVariant* csum_v; + while (g_variant_iter_loop (viter, "(&s@ay)", &name, &csum_v)) + { + g_autofree char *checksum = ostree_checksum_from_bytes_v (csum_v); + g_print ("%s %s\n", name, checksum); + } + return TRUE; +} + +static gboolean +do_print_metadata_key (OstreeRepo *repo, + const char *resolved_rev, + gboolean detached, + const char *key, + GError **error) +{ + g_autoptr(GVariant) commit = NULL; + g_autoptr(GVariant) metadata = NULL; + + if (!detached) + { + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + resolved_rev, &commit, error)) + return FALSE; + /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */ + metadata = g_variant_get_child_value (commit, 0); + } + else + { + if (!ostree_repo_read_commit_detached_metadata (repo, resolved_rev, &metadata, + NULL, error)) + return FALSE; + if (metadata == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No detached metadata for commit %s", resolved_rev); + return FALSE; + } + } + + g_autoptr(GVariant) value = g_variant_lookup_value (metadata, key, NULL); + if (!value) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No such metadata key '%s'", key); + return FALSE; + } + + if (opt_no_byteswap) + { + g_autofree char *formatted = g_variant_print (value, TRUE); + g_print ("%s\n", formatted); + } + else + ot_dump_variant (value); + return TRUE; +} + +static gboolean +do_print_sizes (OstreeRepo *repo, + const char *rev, + GError **error) +{ + g_autoptr(GVariant) commit = NULL; + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, rev, + &commit, error)) + { + g_prefix_error (error, "Failed to read commit: "); + return FALSE; + } + + g_autoptr(GPtrArray) sizes = NULL; + if (!ostree_commit_get_object_sizes (commit, &sizes, error)) + return FALSE; + + gint64 new_archived = 0; + gint64 new_unpacked = 0; + gsize new_objects = 0; + gint64 archived = 0; + gint64 unpacked = 0; + gsize objects = 0; + for (guint i = 0; i < sizes->len; i++) + { + OstreeCommitSizesEntry *entry = sizes->pdata[i]; + + archived += entry->archived; + unpacked += entry->unpacked; + objects++; + + gboolean exists; + if (!ostree_repo_has_object (repo, entry->objtype, entry->checksum, + &exists, NULL, error)) + return FALSE; + + if (!exists) + { + /* Object not in local repo */ + new_archived += entry->archived; + new_unpacked += entry->unpacked; + new_objects++; + } + } + + g_autofree char *new_archived_str = g_format_size (new_archived); + g_autofree char *archived_str = g_format_size (archived); + g_autofree char *new_unpacked_str = g_format_size (new_unpacked); + g_autofree char *unpacked_str = g_format_size (unpacked); + g_print ("Compressed size (needed/total): %s/%s\n" + "Unpacked size (needed/total): %s/%s\n" + "Number of objects (needed/total): %" G_GSIZE_FORMAT "/%" G_GSIZE_FORMAT "\n", + new_archived_str, archived_str, + new_unpacked_str, unpacked_str, + new_objects, objects); + + return TRUE; +} + +static gboolean +print_object (OstreeRepo *repo, + OstreeObjectType objtype, + const char *checksum, + GError **error) +{ + OstreeDumpFlags flags = OSTREE_DUMP_NONE; + + g_autoptr(GVariant) variant = NULL; + if (!ostree_repo_load_variant (repo, objtype, checksum, + &variant, error)) + return FALSE; + if (opt_raw) + flags |= OSTREE_DUMP_RAW; + if (opt_no_byteswap) + flags |= OSTREE_DUMP_UNSWAPPED; + ot_dump_object (objtype, checksum, variant, flags); + +#ifndef OSTREE_DISABLE_GPGME + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + g_autoptr(OstreeGpgVerifyResult) result = NULL; + g_autoptr(GError) local_error = NULL; + g_autoptr(GFile) gpg_homedir = opt_gpg_homedir ? g_file_new_for_path (opt_gpg_homedir) : NULL; + + if (opt_gpg_verify_remote) + { + result = ostree_repo_verify_commit_for_remote (repo, checksum, opt_gpg_verify_remote, + NULL, &local_error); + } + else + { + result = ostree_repo_verify_commit_ext (repo, checksum, + gpg_homedir, NULL, NULL, + &local_error); + } + + if (g_error_matches (local_error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE)) + { + /* Ignore */ + } + else if (local_error != NULL) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + else + { + guint n_sigs = ostree_gpg_verify_result_count_all (result); + g_print ("Found %u signature%s:\n", n_sigs, n_sigs == 1 ? "" : "s"); + + g_autoptr(GString) buffer = g_string_sized_new (256); + for (guint ii = 0; ii < n_sigs; ii++) + { + g_string_append_c (buffer, '\n'); + ostree_gpg_verify_result_describe (result, ii, buffer, " ", + OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT); + } + + g_print ("%s", buffer->str); + } + } +#endif /* OSTREE_DISABLE_GPGME */ + + return TRUE; +} + +static gboolean +print_if_found (OstreeRepo *repo, + OstreeObjectType objtype, + const char *checksum, + gboolean *inout_was_found, + GCancellable *cancellable, + GError **error) +{ + gboolean have_object = FALSE; + + if (*inout_was_found) + return TRUE; + + if (!ostree_repo_has_object (repo, objtype, checksum, &have_object, + cancellable, error)) + return FALSE; + if (have_object) + { + if (!print_object (repo, objtype, checksum, error)) + return FALSE; + *inout_was_found = TRUE; + } + + return TRUE; +} + +gboolean +ostree_builtin_show (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new ("OBJECT"); + + g_autoptr(OstreeRepo) repo = NULL; + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (argc <= 1) + { + ot_util_usage_error (context, "An object argument is required", error); + return FALSE; + } + const char *rev = argv[1]; + + g_autofree char *resolved_rev = NULL; + if (opt_print_metadata_key || opt_print_detached_metadata_key) + { + gboolean detached = opt_print_detached_metadata_key != NULL; + const char *key = detached ? opt_print_detached_metadata_key : opt_print_metadata_key; + if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error)) + return FALSE; + + if (!do_print_metadata_key (repo, resolved_rev, detached, key, error)) + return FALSE; + } + else if (opt_print_related) + { + if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error)) + return FALSE; + + if (!do_print_related (repo, rev, resolved_rev, error)) + return FALSE; + } + else if (opt_print_variant_type) + { + if (!do_print_variant_generic (G_VARIANT_TYPE (opt_print_variant_type), rev, error)) + return FALSE; + } + else if (opt_print_sizes) + { + if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error)) + return FALSE; + + if (!do_print_sizes (repo, resolved_rev, error)) + return FALSE; + } + else + { + gboolean found = FALSE; + if (!ostree_validate_checksum_string (rev, NULL)) + { + if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error)) + return FALSE; + if (!print_object (repo, OSTREE_OBJECT_TYPE_COMMIT, resolved_rev, error)) + return FALSE; + } + else + { + if (!print_if_found (repo, OSTREE_OBJECT_TYPE_COMMIT, rev, + &found, cancellable, error)) + return FALSE; + if (!print_if_found (repo, OSTREE_OBJECT_TYPE_DIR_META, rev, + &found, cancellable, error)) + return FALSE; + if (!print_if_found (repo, OSTREE_OBJECT_TYPE_DIR_TREE, rev, + &found, cancellable, error)) + return FALSE; + if (!found) + { + g_autoptr(GFileInfo) finfo = NULL; + g_autoptr(GVariant) xattrs = NULL; + + if (!ostree_repo_load_file (repo, rev, NULL, &finfo, &xattrs, + cancellable, error)) + return FALSE; + + g_print ("Object: %s\nType: %s\n", rev, ostree_object_type_to_string (OSTREE_OBJECT_TYPE_FILE)); + GFileType filetype = g_file_info_get_file_type (finfo); + g_print ("File Type: "); + switch (filetype) + { + case G_FILE_TYPE_REGULAR: + g_print ("regular\n"); + g_print ("Size: %" G_GUINT64_FORMAT "\n", g_file_info_get_size (finfo)); + break; + case G_FILE_TYPE_SYMBOLIC_LINK: + g_print ("symlink\n"); + g_print ("Target: %s\n", g_file_info_get_symlink_target (finfo)); + break; + default: + g_printerr ("(unknown type %u)\n", (guint)filetype); + } + + g_print ("Mode: 0%04o\n", g_file_info_get_attribute_uint32 (finfo, "unix::mode")); + g_print ("Uid: %u\n", g_file_info_get_attribute_uint32 (finfo, "unix::uid")); + g_print ("Gid: %u\n", g_file_info_get_attribute_uint32 (finfo, "unix::gid")); + + g_print ("Extended Attributes: "); + if (xattrs) + { + g_autofree char *xattr_string = g_variant_print (xattrs, TRUE); + g_print ("{ %s }\n", xattr_string); + } + else + { + g_print ("(none)\n"); + } + } + } + } + + return TRUE; +} diff --git a/src/ostree/ot-builtin-sign.c b/src/ostree/ot-builtin-sign.c new file mode 100644 index 0000000..c777748 --- /dev/null +++ b/src/ostree/ot-builtin-sign.c @@ -0,0 +1,264 @@ +/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */ + +/* + * Copyright (C) 2015 Colin Walters + * Copyright (C) 2019 Denis Pynkin (d4s) + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" +#include "ostree-core-private.h" +#include "ostree-sign.h" + +static gboolean opt_delete; +static gboolean opt_verify; +static char *opt_sign_name; +static char *opt_filename; +static char *opt_keysdir; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-sign.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "delete", 'd', 0, G_OPTION_ARG_NONE, &opt_delete, "Delete signatures having any of the KEY-IDs", NULL}, + { "verify", 0, 0, G_OPTION_ARG_NONE, &opt_verify, "Verify signatures", NULL}, + { "sign-type", 's', 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"}, +#if defined(HAVE_LIBSODIUM) + { "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_filename, "Read key(s) from file", "NAME"}, + { "keys-dir", 0, 0, G_OPTION_ARG_STRING, &opt_keysdir, "Redefine system-wide directories with public and revoked keys for verification", "NAME"}, +#endif + { NULL } +}; + +static void +usage_error (GOptionContext *context, const char *message, GError **error) +{ + g_autofree char *help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s", help); + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, message); +} + +gboolean +ostree_builtin_sign (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr (GOptionContext) context = NULL; + g_autoptr (OstreeRepo) repo = NULL; + g_autoptr (OstreeSign) sign = NULL; + g_autofree char *resolved_commit = NULL; + g_autofree char *success_message = NULL; + const char *commit; + char **key_ids; + int n_key_ids, ii; + gboolean ret = FALSE; + + context = g_option_context_new ("COMMIT KEY-ID..."); + + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + usage_error (context, "Need a COMMIT to sign or verify", error); + goto out; + } + + commit = argv[1]; + + /* Verification could be done via system files with public keys */ + if (!opt_verify && + !opt_filename && + argc < 3) + { + usage_error (context, "Need at least one KEY-ID to sign with", error); + goto out; + } + + key_ids = argv + 2; + n_key_ids = argc - 2; + + if (!ostree_repo_resolve_rev (repo, commit, FALSE, &resolved_commit, error)) + goto out; + + /* Initialize crypto system */ + opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519; + + sign = ostree_sign_get_by_name (opt_sign_name, error); + if (sign == NULL) + goto out; + + for (ii = 0; ii < n_key_ids; ii++) + { + g_autoptr (GVariant) sk = NULL; + g_autoptr (GVariant) pk = NULL; + + if (opt_verify) + { + g_autoptr (GError) local_error = NULL; + + + // Pass the key as a string + pk = g_variant_new_string(key_ids[ii]); + + if (!ostree_sign_set_pk (sign, pk, &local_error)) + continue; + + if (ostree_sign_commit_verify (sign, + repo, + resolved_commit, + &success_message, + cancellable, + &local_error)) + { + g_assert (success_message); + g_print ("%s\n", success_message); + ret = TRUE; + goto out; + } + } + else + { + // Pass the key as a string + sk = g_variant_new_string(key_ids[ii]); + if (!ostree_sign_set_sk (sign, sk, error)) + { + ret = FALSE; + goto out; + } + + ret = ostree_sign_commit (sign, + repo, + resolved_commit, + cancellable, + error); + if (ret != TRUE) + goto out; + } + } + + /* Try to verify with user-provided file or system configuration */ + if (opt_verify) + { + if ((n_key_ids == 0) || opt_filename) + { + g_autoptr (GVariantBuilder) builder = NULL; + g_autoptr (GVariant) options = NULL; + + builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + /* Use custom directory with public and revoked keys instead of system-wide directories */ + if (opt_keysdir) + g_variant_builder_add (builder, "{sv}", "basedir", g_variant_new_string (opt_keysdir)); + /* The last chance for verification source -- system files */ + if (opt_filename) + g_variant_builder_add (builder, "{sv}", "filename", g_variant_new_string (opt_filename)); + options = g_variant_builder_end (builder); + + if (!ostree_sign_load_pk (sign, options, error)) + goto out; + + if (ostree_sign_commit_verify (sign, + repo, + resolved_commit, + &success_message, + cancellable, + error)) + { + g_print ("%s\n", success_message); + ret = TRUE; + } + } /* Check via file */ + } + else + { + /* Sign with keys from provided file */ + if (opt_filename) + { + g_autoptr (GFile) keyfile = NULL; + g_autoptr (GFileInputStream) key_stream_in = NULL; + g_autoptr (GDataInputStream) key_data_in = NULL; + + if (!g_file_test (opt_filename, G_FILE_TEST_IS_REGULAR)) + { + g_warning ("Can't open file '%s' with keys", opt_filename); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "File object '%s' is not a regular file", opt_filename); + goto out; + } + + keyfile = g_file_new_for_path (opt_filename); + key_stream_in = g_file_read (keyfile, NULL, error); + if (key_stream_in == NULL) + goto out; + + key_data_in = g_data_input_stream_new (G_INPUT_STREAM(key_stream_in)); + g_assert (key_data_in != NULL); + + /* Use simple file format with just a list of base64 public keys per line */ + while (TRUE) + { + gsize len = 0; + g_autofree char *line = g_data_input_stream_read_line (key_data_in, &len, NULL, error); + g_autoptr (GVariant) sk = NULL; + + if (*error != NULL) + goto out; + + if (line == NULL) + break; + + + // Pass the key as a string + sk = g_variant_new_string(line); + if (!ostree_sign_set_sk (sign, sk, error)) + { + ret = FALSE; + goto out; + } + + ret = ostree_sign_commit (sign, + repo, + resolved_commit, + cancellable, + error); + if (ret != TRUE) + goto out; + } + } + } + // No valid signature found + if (opt_verify && (ret != TRUE) && (*error == NULL)) + g_set_error_literal (error, + G_IO_ERROR, G_IO_ERROR_FAILED, + "No valid signatures found"); + +out: + /* It is possible to have an error due multiple signatures check */ + if (ret == TRUE) + g_clear_error (error); + return ret; +} diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c new file mode 100644 index 0000000..4f9ff2b --- /dev/null +++ b/src/ostree/ot-builtin-static-delta.c @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "ostree-cmdprivate.h" +#include "ot-main.h" +#include "otutil.h" + +static char *opt_from_rev; +static char *opt_to_rev; +static char *opt_min_fallback_size; +static char *opt_max_bsdiff_size; +static char *opt_max_chunk_size; +static char *opt_endianness; +static char *opt_filename; +static gboolean opt_empty; +static gboolean opt_swap_endianness; +static gboolean opt_inline; +static gboolean opt_disable_bsdiff; +static gboolean opt_if_not_exists; + +#define BUILTINPROTO(name) static gboolean ot_static_delta_builtin_ ## name (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) + +BUILTINPROTO(list); +BUILTINPROTO(show); +BUILTINPROTO(delete); +BUILTINPROTO(generate); +BUILTINPROTO(apply_offline); + +#undef BUILTINPROTO + +static OstreeCommand static_delta_subcommands[] = { + { "list", OSTREE_BUILTIN_FLAG_NONE, + ot_static_delta_builtin_list, + "List static delta files" }, + { "show", OSTREE_BUILTIN_FLAG_NONE, + ot_static_delta_builtin_show, + "Dump information on a delta" }, + { "delete", OSTREE_BUILTIN_FLAG_NONE, + ot_static_delta_builtin_delete, + "Remove a delta" }, + { "generate", OSTREE_BUILTIN_FLAG_NONE, + ot_static_delta_builtin_generate, + "Generate static delta files" }, + { "apply-offline", OSTREE_BUILTIN_FLAG_NONE, + ot_static_delta_builtin_apply_offline, + "Apply static delta file" }, + { NULL, 0, NULL, NULL } +}; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-static-delta.xml) when changing the option list(s). + */ + +static GOptionEntry generate_options[] = { + { "from", 0, 0, G_OPTION_ARG_STRING, &opt_from_rev, "Create delta from revision REV", "REV" }, + { "empty", 0, 0, G_OPTION_ARG_NONE, &opt_empty, "Create delta from scratch", NULL }, + { "inline", 0, 0, G_OPTION_ARG_NONE, &opt_inline, "Inline delta parts into main delta", NULL }, + { "to", 0, 0, G_OPTION_ARG_STRING, &opt_to_rev, "Create delta to revision REV", "REV" }, + { "disable-bsdiff", 0, 0, G_OPTION_ARG_NONE, &opt_disable_bsdiff, "Disable use of bsdiff", NULL }, + { "if-not-exists", 'n', 0, G_OPTION_ARG_NONE, &opt_if_not_exists, "Only generate if a delta does not already exist", NULL }, + { "set-endianness", 0, 0, G_OPTION_ARG_STRING, &opt_endianness, "Choose metadata endianness ('l' or 'B')", "ENDIAN" }, + { "swap-endianness", 0, 0, G_OPTION_ARG_NONE, &opt_swap_endianness, "Swap metadata endianness from host order", NULL }, + { "min-fallback-size", 0, 0, G_OPTION_ARG_STRING, &opt_min_fallback_size, "Minimum uncompressed size in megabytes for individual HTTP request", NULL}, + { "max-bsdiff-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_bsdiff_size, "Maximum size in megabytes to consider bsdiff compression for input files", NULL}, + { "max-chunk-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_chunk_size, "Maximum size of delta chunks in megabytes", NULL}, + { "filename", 0, 0, G_OPTION_ARG_FILENAME, &opt_filename, "Write the delta content to PATH (a directory). If not specified, the OSTree repository is used", "PATH"}, + { NULL } +}; + +static GOptionEntry apply_offline_options[] = { + { NULL } +}; + +static GOptionEntry list_options[] = { + { NULL } +}; + +static void +static_delta_usage (char **argv, + gboolean is_error) +{ + OstreeCommand *command = static_delta_subcommands; + void (*print_func) (const gchar *format, ...); + + if (is_error) + print_func = g_printerr; + else + print_func = g_print; + + print_func ("Usage:\n"); + print_func (" ostree static-delta [OPTION...] COMMAND\n\n"); + print_func ("Builtin \"static-delta\" Commands:\n"); + + while (command->name) + { + if ((command->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0) + print_func (" %-17s%s\n", command->name, command->description ?: ""); + command++; + } + + print_func ("\n"); +} + +static gboolean +ot_static_delta_builtin_list (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GOptionContext) context = g_option_context_new (""); + if (!ostree_option_context_parse (context, list_options, &argc, &argv, + invocation, &repo, cancellable, error)) + return FALSE; + + g_autoptr(GPtrArray) delta_names = NULL; + if (!ostree_repo_list_static_delta_names (repo, &delta_names, cancellable, error)) + return FALSE; + + if (delta_names->len == 0) + g_print ("(No static deltas)\n"); + else + { + for (guint i = 0; i < delta_names->len; i++) + g_print ("%s\n", (char*)delta_names->pdata[i]); + } + + return TRUE; +} + +static gboolean +ot_static_delta_builtin_show (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + + g_autoptr(GOptionContext) context = g_option_context_new (""); + + g_autoptr(OstreeRepo) repo = NULL; + if (!ostree_option_context_parse (context, list_options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (argc < 3) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "DELTA must be specified"); + return FALSE; + } + + const char *delta_id = argv[2]; + + if (!ostree_cmd__private__ ()->ostree_static_delta_dump (repo, delta_id, cancellable, error)) + return FALSE; + + return TRUE; +} + +static gboolean +ot_static_delta_builtin_delete (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new (""); + + g_autoptr(OstreeRepo) repo = NULL; + if (!ostree_option_context_parse (context, list_options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (argc < 3) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "DELTA must be specified"); + return FALSE; + } + + const char *delta_id = argv[2]; + + if (!ostree_cmd__private__ ()->ostree_static_delta_delete (repo, delta_id, cancellable, error)) + return FALSE; + + return TRUE; +} + + +static gboolean +ot_static_delta_builtin_generate (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new ("[TO]"); + g_autoptr(OstreeRepo) repo = NULL; + if (!ostree_option_context_parse (context, generate_options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (!ostree_ensure_repo_writable (repo, error)) + return FALSE; + + if (argc >= 3 && opt_to_rev == NULL) + opt_to_rev = argv[2]; + + if (argc < 3 && opt_to_rev == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "TO revision must be specified"); + return FALSE; + } + else + { + const char *from_source; + g_autofree char *from_resolved = NULL; + g_autofree char *to_resolved = NULL; + g_autofree char *from_parent_str = NULL; + g_autoptr(GVariantBuilder) parambuilder = NULL; + int endianness; + + g_assert (opt_to_rev); + + if (opt_empty) + { + if (opt_from_rev) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot specify both --empty and --from=REV"); + return FALSE; + } + from_source = NULL; + } + else if (opt_from_rev == NULL) + { + from_parent_str = g_strconcat (opt_to_rev, "^", NULL); + from_source = from_parent_str; + } + else + { + from_source = opt_from_rev; + } + + if (from_source) + { + if (!ostree_repo_resolve_rev (repo, from_source, FALSE, &from_resolved, error)) + return FALSE; + } + if (!ostree_repo_resolve_rev (repo, opt_to_rev, FALSE, &to_resolved, error)) + return FALSE; + + if (opt_if_not_exists) + { + gboolean does_exist; + g_autofree char *delta_id = from_resolved ? g_strconcat (from_resolved, "-", to_resolved, NULL) : g_strdup (to_resolved); + if (!ostree_cmd__private__ ()->ostree_static_delta_query_exists (repo, delta_id, &does_exist, cancellable, error)) + return FALSE; + if (does_exist) + { + g_print ("Delta %s already exists.\n", delta_id); + return TRUE; + } + } + + if (opt_endianness) + { + if (strcmp (opt_endianness, "l") == 0) + endianness = G_LITTLE_ENDIAN; + else if (strcmp (opt_endianness, "B") == 0) + endianness = G_BIG_ENDIAN; + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid endianness '%s'", opt_endianness); + return FALSE; + } + } + else + endianness = G_BYTE_ORDER; + + if (opt_swap_endianness) + { + switch (endianness) + { + case G_LITTLE_ENDIAN: + endianness = G_BIG_ENDIAN; + break; + case G_BIG_ENDIAN: + endianness = G_LITTLE_ENDIAN; + break; + default: + g_assert_not_reached (); + } + } + + parambuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + if (opt_min_fallback_size) + g_variant_builder_add (parambuilder, "{sv}", + "min-fallback-size", g_variant_new_uint32 (g_ascii_strtoull (opt_min_fallback_size, NULL, 10))); + if (opt_max_bsdiff_size) + g_variant_builder_add (parambuilder, "{sv}", + "max-bsdiff-size", g_variant_new_uint32 (g_ascii_strtoull (opt_max_bsdiff_size, NULL, 10))); + if (opt_max_chunk_size) + g_variant_builder_add (parambuilder, "{sv}", + "max-chunk-size", g_variant_new_uint32 (g_ascii_strtoull (opt_max_chunk_size, NULL, 10))); + if (opt_disable_bsdiff) + g_variant_builder_add (parambuilder, "{sv}", + "bsdiff-enabled", g_variant_new_boolean (FALSE)); + if (opt_inline) + g_variant_builder_add (parambuilder, "{sv}", + "inline-parts", g_variant_new_boolean (TRUE)); + if (opt_filename) + g_variant_builder_add (parambuilder, "{sv}", + "filename", g_variant_new_bytestring (opt_filename)); + + g_variant_builder_add (parambuilder, "{sv}", "verbose", g_variant_new_boolean (TRUE)); + if (opt_endianness || opt_swap_endianness) + g_variant_builder_add (parambuilder, "{sv}", "endianness", g_variant_new_uint32 (endianness)); + + g_print ("Generating static delta:\n"); + g_print (" From: %s\n", from_resolved ? from_resolved : "empty"); + g_print (" To: %s\n", to_resolved); + { g_autoptr(GVariant) params = g_variant_ref_sink (g_variant_builder_end (parambuilder)); + if (!ostree_repo_static_delta_generate (repo, OSTREE_STATIC_DELTA_GENERATE_OPT_MAJOR, + from_resolved, to_resolved, NULL, + params, + cancellable, error)) + return FALSE; + } + + } + + return TRUE; +} + +static gboolean +ot_static_delta_builtin_apply_offline (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + + context = g_option_context_new (""); + if (!ostree_option_context_parse (context, apply_offline_options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + if (!ostree_ensure_repo_writable (repo, error)) + return FALSE; + + if (argc < 3) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "PATH must be specified"); + return FALSE; + } + + const char *patharg = argv[2]; + g_autoptr(GFile) path = g_file_new_for_path (patharg); + + if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) + return FALSE; + + if (!ostree_repo_static_delta_execute_offline (repo, path, FALSE, cancellable, error)) + return FALSE; + + if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) + return FALSE; + + return TRUE; +} + +gboolean +ostree_builtin_static_delta (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + gboolean want_help = FALSE; + const char *cmdname = NULL; + for (int i = 1; i < argc; i++) + { + if (argv[i][0] != '-') + { + cmdname = argv[i]; + break; + } + else if (g_str_equal (argv[i], "--help") || g_str_equal (argv[i], "-h")) + { + want_help = TRUE; + break; + } + } + + if (!cmdname && !want_help) + { + static_delta_usage (argv, TRUE); + return glnx_throw (error, "No command specified"); + } + + OstreeCommand *command = NULL; + if (cmdname) + { + command = static_delta_subcommands; + while (command->name) + { + if (g_strcmp0 (cmdname, command->name) == 0) + break; + command++; + } + } + + if (want_help && command == NULL) + { + static_delta_usage (argv, FALSE); + return TRUE; /* Note early return */ + } + + if (!command->fn) + { + static_delta_usage (argv, TRUE); + return glnx_throw (error, "Unknown \"static-delta\" subcommand '%s'", cmdname); + } + + g_autofree char *prgname = g_strdup_printf ("%s %s", g_get_prgname (), cmdname); + g_set_prgname (prgname); + + OstreeCommandInvocation sub_invocation = { .command = command }; + return command->fn (argc, argv, &sub_invocation, cancellable, error); +} diff --git a/src/ostree/ot-builtin-summary.c b/src/ostree/ot-builtin-summary.c new file mode 100644 index 0000000..0938f11 --- /dev/null +++ b/src/ostree/ot-builtin-summary.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2014 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-repo-private.h" +#include "ot-dump.h" +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" +#include "ostree-sign.h" + +static gboolean opt_update, opt_view, opt_raw; +static char **opt_gpg_key_ids; +static char *opt_gpg_homedir; +static char **opt_key_ids; +static char *opt_sign_name; +static char **opt_metadata; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-summary.xml) when changing the option list. + */ + +static GOptionEntry options[] = { + { "update", 'u', 0, G_OPTION_ARG_NONE, &opt_update, "Update the summary", NULL }, + { "view", 'v', 0, G_OPTION_ARG_NONE, &opt_view, "View the local summary file", NULL }, + { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "View the raw bytes of the summary file", NULL }, + { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_gpg_key_ids, "GPG Key ID to sign the summary with", "KEY-ID"}, + { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, + { "sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "Key ID to sign the summary with", "KEY-ID"}, + { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"}, + { "add-metadata", 'm', 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata, "Additional metadata field to add to the summary", "KEY=VALUE" }, + { NULL } +}; + +/* Take arguments of the form KEY=VALUE and put them into an a{sv} variant. The + * value arguments must be parsable using g_variant_parse(). */ +static GVariant * +build_additional_metadata (const char * const *args, + GError **error) +{ + g_autoptr(GVariantBuilder) builder = NULL; + + builder = g_variant_builder_new (G_VARIANT_TYPE_VARDICT); + + for (gsize i = 0; args[i] != NULL; i++) + { + const gchar *equals = strchr (args[i], '='); + g_autofree gchar *key = NULL; + const gchar *value_str; + g_autoptr(GVariant) value = NULL; + + if (equals == NULL) + return glnx_null_throw (error, + "Missing '=' in KEY=VALUE metadata '%s'", args[i]); + + key = g_strndup (args[i], equals - args[i]); + value_str = equals + 1; + + value = g_variant_parse (NULL, value_str, NULL, NULL, error); + if (value == NULL) + return glnx_prefix_error_null (error, "Error parsing variant ‘%s’: ", value_str); + + g_variant_builder_add (builder, "{sv}", key, value); + } + + return g_variant_ref_sink (g_variant_builder_end (builder)); +} + +gboolean +ostree_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr (OstreeSign) sign = NULL; + OstreeDumpFlags flags = OSTREE_DUMP_NONE; + + context = g_option_context_new (""); + + if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error)) + return FALSE; + + /* Initialize crypto system */ + if (opt_key_ids) + { + opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519; + + sign = ostree_sign_get_by_name (opt_sign_name, error); + if (sign == NULL) + return FALSE; + } + + if (opt_update) + { + g_autoptr(GVariant) additional_metadata = NULL; + + if (!ostree_ensure_repo_writable (repo, error)) + return FALSE; + + if (opt_metadata != NULL) + { + additional_metadata = build_additional_metadata ((const char * const *) opt_metadata, error); + if (additional_metadata == NULL) + return FALSE; + } + + const char *collection_id = ostree_repo_get_collection_id (repo); + + /* Write out a new metadata commit for the repository. */ + if (collection_id != NULL) + { + OstreeCollectionRef collection_ref = { (gchar *) collection_id, (gchar *) OSTREE_REPO_METADATA_REF }; + g_autofree char *old_ostree_metadata_checksum = NULL; + g_autofree gchar *new_ostree_metadata_checksum = NULL; + g_autoptr(OstreeMutableTree) mtree = NULL; + g_autoptr(OstreeRepoFile) repo_file = NULL; + g_autoptr(GVariantDict) new_summary_commit_dict = NULL; + g_autoptr(GVariant) new_summary_commit = NULL; + + if (!ostree_repo_resolve_rev (repo, OSTREE_REPO_METADATA_REF, + TRUE, &old_ostree_metadata_checksum, error)) + return FALSE; + + /* Add bindings to the metadata. */ + new_summary_commit_dict = g_variant_dict_new (additional_metadata); + g_variant_dict_insert (new_summary_commit_dict, OSTREE_COMMIT_META_KEY_COLLECTION_BINDING, + "s", collection_ref.collection_id); + g_variant_dict_insert_value (new_summary_commit_dict, OSTREE_COMMIT_META_KEY_REF_BINDING, + g_variant_new_strv ((const gchar * const *) &collection_ref.ref_name, 1)); + new_summary_commit = g_variant_dict_end (new_summary_commit_dict); + + if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) + return FALSE; + + /* Set up an empty mtree. */ + mtree = ostree_mutable_tree_new (); + + glnx_unref_object GFileInfo *fi = g_file_info_new (); + g_file_info_set_attribute_uint32 (fi, "unix::uid", 0); + g_file_info_set_attribute_uint32 (fi, "unix::gid", 0); + g_file_info_set_attribute_uint32 (fi, "unix::mode", (0755 | S_IFDIR)); + + g_autofree guchar *csum_raw = NULL; + g_autofree char *csum = NULL; + + g_autoptr(GVariant) dirmeta = ostree_create_directory_metadata (fi, NULL /* xattrs */); + + if (!ostree_repo_write_metadata (repo, OSTREE_OBJECT_TYPE_DIR_META, NULL, + dirmeta, &csum_raw, cancellable, error)) + return FALSE; + + csum = ostree_checksum_from_bytes (csum_raw); + ostree_mutable_tree_set_metadata_checksum (mtree, csum); + + if (!ostree_repo_write_mtree (repo, mtree, (GFile **) &repo_file, NULL, error)) + return FALSE; + + if (!ostree_repo_write_commit (repo, old_ostree_metadata_checksum, + NULL /* subject */, NULL /* body */, + new_summary_commit, repo_file, &new_ostree_metadata_checksum, + NULL, error)) + return FALSE; + if (opt_gpg_key_ids != NULL) + { + for (const char * const *iter = (const char * const *) opt_gpg_key_ids; + iter != NULL && *iter != NULL; iter++) + { + const char *key_id = *iter; + + if (!ostree_repo_sign_commit (repo, + new_ostree_metadata_checksum, + key_id, + opt_gpg_homedir, + cancellable, + error)) + return FALSE; + } + } + + if (opt_key_ids) + { + char **iter; + for (iter = opt_key_ids; iter && *iter; iter++) + { + const char *keyid = *iter; + g_autoptr (GVariant) secret_key = NULL; + + secret_key = g_variant_new_string (keyid); + if (!ostree_sign_set_sk (sign, secret_key, error)) + return FALSE; + + if (!ostree_sign_commit (sign, + repo, + new_ostree_metadata_checksum, + cancellable, + error)) + return FALSE; + } + } + + ostree_repo_transaction_set_collection_ref (repo, &collection_ref, + new_ostree_metadata_checksum); + + if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) + return FALSE; + } + + /* Regenerate and sign the conventional summary file. */ + if (!ostree_repo_regenerate_summary (repo, additional_metadata, cancellable, error)) + return FALSE; + +#ifndef OSTREE_DISABLE_GPGME + if (opt_gpg_key_ids) + { + if (!ostree_repo_add_gpg_signature_summary (repo, + (const gchar **) opt_gpg_key_ids, + opt_gpg_homedir, + cancellable, + error)) + return FALSE; + } +#endif + if (opt_key_ids) + { + g_autoptr (GVariant) secret_keys = NULL; + g_autoptr (GVariantBuilder) sk_builder = NULL; + + sk_builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); + + char **iter; + for (iter = opt_key_ids; iter && *iter; iter++) + { + const char *keyid = *iter; + GVariant *secret_key = NULL; + + /* Currently only strings are used as keys + * for supported signature types */ + secret_key = g_variant_new_string (keyid); + + g_variant_builder_add (sk_builder, "v", secret_key); + } + + secret_keys = g_variant_builder_end (sk_builder); + + if (! ostree_sign_summary (sign, + repo, + secret_keys, + cancellable, + error)) + return FALSE; + } + } + else if (opt_view || opt_raw) + { + g_autoptr(GBytes) summary_data = NULL; + + if (opt_raw) + flags |= OSTREE_DUMP_RAW; + + glnx_autofd int fd = -1; + if (!glnx_openat_rdonly (repo->repo_dir_fd, "summary", TRUE, &fd, error)) + return FALSE; + summary_data = ot_fd_readall_or_mmap (fd, 0, error); + if (!summary_data) + return FALSE; + + ot_dump_summary_bytes (summary_data, flags); + } + else + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No option specified; use -u to update summary"); + return FALSE; + } + + return TRUE; +} diff --git a/src/ostree/ot-builtin-trivial-httpd.c b/src/ostree/ot-builtin-trivial-httpd.c new file mode 100644 index 0000000..b187754 --- /dev/null +++ b/src/ostree/ot-builtin-trivial-httpd.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +gboolean +ostree_builtin_trivial_httpd (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GPtrArray) new_argv = g_ptr_array_new (); + + g_ptr_array_add (new_argv, PKGLIBEXECDIR "/ostree-trivial-httpd"); + for (int i = 1; i < argc; i++) + g_ptr_array_add (new_argv, argv[i]); + g_ptr_array_add (new_argv, NULL); + execvp (new_argv->pdata[0], (char**)new_argv->pdata); + /* Fall through on error */ + glnx_set_error_from_errno (error); + return FALSE; +} diff --git a/src/ostree/ot-builtins.h b/src/ostree/ot-builtins.h new file mode 100644 index 0000000..e372d35 --- /dev/null +++ b/src/ostree/ot-builtins.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include "config.h" + +#include "ostree.h" + +G_BEGIN_DECLS + +#define BUILTINPROTO(name) gboolean ostree_builtin_ ## name (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) + +BUILTINPROTO(admin); +BUILTINPROTO(cat); +BUILTINPROTO(config); +BUILTINPROTO(checkout); +BUILTINPROTO(checksum); +BUILTINPROTO(commit); +BUILTINPROTO(diff); +BUILTINPROTO(export); +BUILTINPROTO(find_remotes); +BUILTINPROTO(create_usb); +#ifndef OSTREE_DISABLE_GPGME +BUILTINPROTO(gpg_sign); +#endif +BUILTINPROTO(init); +BUILTINPROTO(log); +BUILTINPROTO(pull); +BUILTINPROTO(pull_local); +BUILTINPROTO(ls); +BUILTINPROTO(prune); +BUILTINPROTO(refs); +BUILTINPROTO(reset); +BUILTINPROTO(fsck); +BUILTINPROTO(sign); +BUILTINPROTO(show); +BUILTINPROTO(static_delta); +BUILTINPROTO(summary); +BUILTINPROTO(rev_parse); +BUILTINPROTO(remote); +BUILTINPROTO(write_refs); +BUILTINPROTO(trivial_httpd); + +#undef BUILTINPROTO + +G_END_DECLS diff --git a/src/ostree/ot-dump.c b/src/ostree/ot-dump.c new file mode 100644 index 0000000..38f3730 --- /dev/null +++ b/src/ostree/ot-dump.c @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2011 Colin Walters + * Copyright (C) 2013 Stef Walter + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Stef Walter + * Colin Walters + */ + +#include "config.h" + +#include + +#include "ostree-repo-private.h" +#include "ostree-repo-static-delta-private.h" +#include "ot-dump.h" +#include "otutil.h" +#include "ot-admin-functions.h" + +void +ot_dump_variant (GVariant *variant) +{ + g_autofree char *formatted_variant = NULL; + g_autoptr(GVariant) byteswapped = NULL; + + if (G_BYTE_ORDER != G_BIG_ENDIAN) + { + byteswapped = g_variant_byteswap (variant); + formatted_variant = g_variant_print (byteswapped, TRUE); + } + else + { + formatted_variant = g_variant_print (variant, TRUE); + } + g_print ("%s\n", formatted_variant); +} + +static gchar * +format_timestamp (guint64 timestamp, + GError **error) +{ + GDateTime *dt; + gchar *str; + + dt = g_date_time_new_from_unix_utc (timestamp); + if (dt == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "Invalid timestamp: %" G_GUINT64_FORMAT, timestamp); + return NULL; + } + + str = g_date_time_format (dt, "%Y-%m-%d %H:%M:%S +0000"); + g_date_time_unref (dt); + + return str; +} + +static gchar * +uint64_secs_to_iso8601 (guint64 secs) +{ + g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (secs); + g_autoptr(GDateTime) local = (dt != NULL) ? g_date_time_to_local (dt) : NULL; + + if (local != NULL) + return g_date_time_format (local, "%FT%T%:::z"); + else + return g_strdup ("invalid"); +} + +static void +dump_indented_lines (const gchar *data) +{ + const char* indent = " "; + const gchar *pos; + + for (;;) + { + pos = strchr (data, '\n'); + if (pos) + { + g_print ("%s%.*s", indent, (int)(pos + 1 - data), data); + data = pos + 1; + } + else + { + if (data[0] != '\0') + g_print ("%s%s\n", indent, data); + break; + } + } +} + +static void +dump_commit (GVariant *variant, + OstreeDumpFlags flags) +{ + const gchar *subject; + const gchar *body; + guint64 timestamp; + g_autofree char *str = NULL; + g_autofree char *version = NULL; + g_autoptr(GError) local_error = NULL; + + /* See OSTREE_COMMIT_GVARIANT_FORMAT */ + g_variant_get (variant, "(a{sv}aya(say)&s&stayay)", NULL, NULL, NULL, + &subject, &body, ×tamp, NULL, NULL); + + timestamp = GUINT64_FROM_BE (timestamp); + str = format_timestamp (timestamp, &local_error); + if (!str) + { + g_assert (local_error); /* Pacify static analysis */ + errx (1, "Failed to read commit: %s", local_error->message); + } + g_autofree char *contents = ostree_commit_get_content_checksum (variant) ?: ""; + g_print ("ContentChecksum: %s\n", contents); + g_print ("Date: %s\n", str); + + if ((version = ot_admin_checksum_version (variant))) + { + g_print ("Version: %s\n", version); + } + + if (subject[0]) + { + g_print ("\n"); + dump_indented_lines (subject); + } + else + { + g_print ("(no subject)\n"); + } + + if (body[0]) + { + g_print ("\n"); + dump_indented_lines (body); + } + g_print ("\n"); +} + +void +ot_dump_object (OstreeObjectType objtype, + const char *checksum, + GVariant *variant, + OstreeDumpFlags flags) +{ + g_print ("%s %s\n", ostree_object_type_to_string (objtype), checksum); + + if (flags & OSTREE_DUMP_UNSWAPPED) + { + g_autofree char *formatted = g_variant_print (variant, TRUE); + g_print ("%s\n", formatted); + } + else if (flags & OSTREE_DUMP_RAW) + { + ot_dump_variant (variant); + return; + } + + switch (objtype) + { + case OSTREE_OBJECT_TYPE_COMMIT: + dump_commit (variant, flags); + break; + /* TODO: Others could be implemented here */ + default: + break; + } +} + +static void +dump_summary_ref (const char *collection_id, + const char *ref_name, + guint64 commit_size, + GVariant *csum_v, + GVariantIter *metadata) +{ + const guchar *csum_bytes; + GError *csum_error = NULL; + g_autofree char *size = NULL; + GVariant *value; + char *key; + + if (collection_id == NULL) + g_print ("* %s\n", ref_name); + else + g_print ("* (%s, %s)\n", collection_id, ref_name); + + size = g_format_size (commit_size); + g_print (" Latest Commit (%s):\n", size); + + csum_bytes = ostree_checksum_bytes_peek_validate (csum_v, &csum_error); + if (csum_error == NULL) + { + char csum[OSTREE_SHA256_STRING_LEN+1]; + + ostree_checksum_inplace_from_bytes (csum_bytes, csum); + g_print (" %s\n", csum); + } + else + { + g_print (" %s\n", csum_error->message); + g_clear_error (&csum_error); + } + + while (g_variant_iter_loop (metadata, "{sv}", &key, &value)) + { + g_autofree gchar *value_str = NULL; + const gchar *pretty_key = NULL; + + if (g_strcmp0 (key, OSTREE_COMMIT_TIMESTAMP) == 0) + { + pretty_key = "Timestamp"; + value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value))); + } + else + { + value_str = g_variant_print (value, FALSE); + } + + /* Print out. */ + if (pretty_key != NULL) + g_print (" %s (%s): %s\n", pretty_key, key, value_str); + else + g_print (" %s: %s\n", key, value_str); + } +} + +static void +dump_summary_refs (const gchar *collection_id, + GVariant *refs) +{ + GVariantIter iter; + GVariant *value; + + g_variant_iter_init (&iter, refs); + + while ((value = g_variant_iter_next_value (&iter)) != NULL) + { + const char *ref_name = NULL; + + g_variant_get_child (value, 0, "&s", &ref_name); + + if (ref_name != NULL) + { + g_autoptr(GVariant) csum_v = NULL; + g_autoptr(GVariantIter) metadata = NULL; + guint64 commit_size; + + g_variant_get_child (value, 1, "(t@aya{sv})", + &commit_size, &csum_v, &metadata); + + dump_summary_ref (collection_id, ref_name, commit_size, csum_v, metadata); + + g_print ("\n"); + } + + g_variant_unref (value); + } +} + +void +ot_dump_summary_bytes (GBytes *summary_bytes, + OstreeDumpFlags flags) +{ + g_autoptr(GVariant) summary = NULL; + g_autoptr(GVariant) refs = NULL; + g_autoptr(GVariant) exts = NULL; + GVariantIter iter; + GVariant *value; + char *key; + + g_return_if_fail (summary_bytes != NULL); + + summary = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE); + + if (flags & OSTREE_DUMP_RAW) + { + ot_dump_variant (summary); + return; + } + + refs = g_variant_get_child_value (summary, 0); + exts = g_variant_get_child_value (summary, 1); + + /* Print the refs, including those with a collection ID specified. */ + const gchar *main_collection_id; + g_autoptr(GVariant) collection_map = NULL; + const gchar *collection_id; + + if (!g_variant_lookup (exts, OSTREE_SUMMARY_COLLECTION_ID, "&s", &main_collection_id)) + main_collection_id = NULL; + + dump_summary_refs (main_collection_id, refs); + + collection_map = g_variant_lookup_value (exts, OSTREE_SUMMARY_COLLECTION_MAP, G_VARIANT_TYPE ("a{sa(s(taya{sv}))}")); + if (collection_map != NULL) + { + g_variant_iter_init (&iter, collection_map); + + while (g_variant_iter_loop (&iter, "{&s@a(s(taya{sv}))}", &collection_id, &refs)) + dump_summary_refs (collection_id, refs); + } + + /* Print out the additional metadata. */ + g_variant_iter_init (&iter, exts); + + while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) + { + g_autofree gchar *value_str = NULL; + const gchar *pretty_key = NULL; + + if (g_strcmp0 (key, OSTREE_SUMMARY_STATIC_DELTAS) == 0) + { + pretty_key = "Static Deltas"; + value_str = g_variant_print (value, FALSE); + } + else if (g_strcmp0 (key, OSTREE_SUMMARY_LAST_MODIFIED) == 0) + { + pretty_key = "Last-Modified"; + value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value))); + } + else if (g_strcmp0 (key, OSTREE_SUMMARY_EXPIRES) == 0) + { + pretty_key = "Expires"; + value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value))); + } + else if (g_strcmp0 (key, OSTREE_SUMMARY_COLLECTION_ID) == 0) + { + pretty_key = "Collection ID"; + value_str = g_variant_dup_string (value, NULL); + } + else if (g_strcmp0 (key, OSTREE_SUMMARY_COLLECTION_MAP) == 0) + { + pretty_key = "Collection Map"; + value_str = g_strdup ("(printed above)"); + } + else + { + value_str = g_variant_print (value, FALSE); + } + + /* Print out. */ + if (pretty_key != NULL) + g_print ("%s (%s): %s\n", pretty_key, key, value_str); + else + g_print ("%s: %s\n", key, value_str); + } +} diff --git a/src/ostree/ot-dump.h b/src/ostree/ot-dump.h new file mode 100644 index 0000000..0e1952a --- /dev/null +++ b/src/ostree/ot-dump.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2013 Stef Walter + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Stef Walter + */ + +#pragma once + +#include + +#include "ostree-core.h" + +typedef enum { + OSTREE_DUMP_NONE = (1 << 0), + OSTREE_DUMP_RAW = (1 << 1), + OSTREE_DUMP_UNSWAPPED = (1 << 2), +} OstreeDumpFlags; + +void ot_dump_variant (GVariant *variant); + +void ot_dump_object (OstreeObjectType objtype, + const char *checksum, + GVariant *variant, + OstreeDumpFlags flags); + +void ot_dump_summary_bytes (GBytes *summary_bytes, + OstreeDumpFlags flags); diff --git a/src/ostree/ot-editor.c b/src/ostree/ot-editor.c new file mode 100644 index 0000000..6aa5713 --- /dev/null +++ b/src/ostree/ot-editor.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2013 Stef Walter + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Stef Walter + */ + +#include "config.h" + +#include "libglnx.h" +#include "otutil.h" +#include "ot-editor.h" + +#include +#include + +#ifndef DEFAULT_EDITOR +#define DEFAULT_EDITOR "vi" +#endif + +/* Logic pulled from git */ + +static const char * +get_editor (void) +{ + const char *editor = g_getenv ("OSTREE_EDITOR"); + const char *terminal = g_getenv ("TERM"); + int terminal_is_dumb = !terminal || g_str_equal (terminal, "dumb"); + + if (!editor && !terminal_is_dumb) + editor = g_getenv ("VISUAL"); + if (!editor) + editor = g_getenv ("EDITOR"); + + if (!editor && terminal_is_dumb) + return NULL; + + if (!editor) + editor = DEFAULT_EDITOR; + + return editor; +} + +char * +ot_editor_prompt (OstreeRepo *repo, + const char *input, + GCancellable *cancellable, + GError **error) +{ + glnx_unref_object GSubprocess *proc = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GFileIOStream) io = NULL; + GOutputStream *output; + const char *editor; + char *ret = NULL; + g_autofree char *args = NULL; + + editor = get_editor (); + if (editor == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Terminal is dumb, but EDITOR unset"); + goto out; + } + + file = g_file_new_tmp (NULL, &io, error); + if (file == NULL) + goto out; + + output = g_io_stream_get_output_stream (G_IO_STREAM (io)); + if (!g_output_stream_write_all (output, input, strlen (input), NULL, cancellable, error) || + !g_io_stream_close (G_IO_STREAM (io), cancellable, error)) + goto out; + + { + g_autofree char *quoted_file = g_shell_quote (gs_file_get_path_cached (file)); + args = g_strconcat (editor, " ", quoted_file, NULL); + } + + proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_INHERIT, error, + "/bin/sh", "-c", args, NULL); + + if (!g_subprocess_wait_check (proc, cancellable, error)) + { + g_prefix_error (error, "There was a problem with the editor '%s'", editor); + goto out; + } + + ret = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (file), NULL, + cancellable, error); + +out: + if (file) + (void )g_file_delete (file, NULL, NULL); + return ret; +} diff --git a/src/ostree/ot-editor.h b/src/ostree/ot-editor.h new file mode 100644 index 0000000..a5615f7 --- /dev/null +++ b/src/ostree/ot-editor.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 Stef Walter + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Stef Walter + */ + +#pragma once + +#include + +#include "ostree.h" + +char * ot_editor_prompt (OstreeRepo *repo, const char *input, + GCancellable *cancellable, GError **error); diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c new file mode 100644 index 0000000..bffa40c --- /dev/null +++ b/src/ostree/ot-main.c @@ -0,0 +1,623 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include + +#include +#include +#include +#include +#include + +#include "ot-main.h" +#include "ostree.h" +#include "ot-admin-functions.h" +#include "otutil.h" + +static char *opt_repo; +static char *opt_sysroot; +static gboolean opt_verbose; +static gboolean opt_version; +static gboolean opt_print_current_dir; + +static GOptionEntry global_entries[] = { + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose, "Print debug information during command processing", NULL }, + { "version", 0, 0, G_OPTION_ARG_NONE, &opt_version, "Print version information and exit", NULL }, + { NULL } +}; + +static GOptionEntry repo_entry[] = { + { "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to current directory or /sysroot/ostree/repo)", "PATH" }, + { NULL } +}; + +static GOptionEntry global_admin_entries[] = { + /* No description since it's hidden from --help output. */ + { "print-current-dir", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_print_current_dir, NULL, NULL }, + { "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Create a new OSTree sysroot at PATH", "PATH" }, + { NULL } +}; + +static GOptionContext * +ostree_option_context_new_with_commands (OstreeCommand *commands) +{ + GOptionContext *context = g_option_context_new ("COMMAND"); + + g_autoptr(GString) summary = g_string_new ("Builtin Commands:"); + + while (commands->name != NULL) + { + if ((commands->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0) + { + g_string_append_printf (summary, "\n %-18s", commands->name); + + if (commands->description != NULL ) + g_string_append_printf (summary, "%s", commands->description); + } + + commands++; + } + + g_option_context_set_summary (context, summary->str); + + return context; +} + +int +ostree_usage (OstreeCommand *commands, + gboolean is_error) +{ + g_autoptr(GOptionContext) context = + ostree_option_context_new_with_commands (commands); + g_option_context_add_main_entries (context, global_entries, NULL); + + g_autofree char *help = g_option_context_get_help (context, FALSE, NULL); + if (is_error) + g_printerr ("%s", help); + else + g_print ("%s", help); + + return (is_error ? 1 : 0); +} + +/* If we're running as root, booted into an OSTree system and have a read-only + * /sysroot, then assume we may need write access. Create a new mount namespace + * if so, and return *out_ns = TRUE. Otherwise, *out_ns = FALSE. + */ +static gboolean +maybe_setup_mount_namespace (gboolean *out_ns, + GError **error) +{ + *out_ns = FALSE; + + /* If we're not root, then we almost certainly can't be remounting anything */ + if (getuid () != 0) + return TRUE; + + /* If the system isn't booted via libostree, also nothing to do */ + if (!glnx_fstatat_allow_noent (AT_FDCWD, "/run/ostree-booted", NULL, 0, error)) + return FALSE; + if (errno == ENOENT) + return TRUE; + + glnx_autofd int sysroot_subdir_fd = glnx_opendirat_with_errno (AT_FDCWD, "/sysroot", TRUE); + if (sysroot_subdir_fd < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "opendirat"); + /* No /sysroot - nothing to do */ + return TRUE; + } + + struct statvfs stvfs; + if (fstatvfs (sysroot_subdir_fd, &stvfs) < 0) + return glnx_throw_errno_prefix (error, "fstatvfs"); + if (stvfs.f_flag & ST_RDONLY) + { + if (unshare (CLONE_NEWNS) < 0) + return glnx_throw_errno_prefix (error, "preparing writable sysroot: unshare (CLONE_NEWNS)"); + + *out_ns = TRUE; + } + + return TRUE; +} + +static void +message_handler (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + /* Make this look like normal console output */ + if (log_level & G_LOG_LEVEL_DEBUG) + g_printerr ("OT: %s\n", message); + else + g_printerr ("%s: %s\n", g_get_prgname (), message); +} + +int +ostree_run (int argc, + char **argv, + OstreeCommand *commands, + GError **res_error) +{ + OstreeCommand *command; + GError *error = NULL; + GCancellable *cancellable = NULL; +#ifndef BUILDOPT_TSAN + g_autofree char *prgname = NULL; +#endif + const char *command_name = NULL; + gboolean success = FALSE; + int in, out; + + /* avoid gvfs (http://bugzilla.gnome.org/show_bug.cgi?id=526454) */ + g_setenv ("GIO_USE_VFS", "local", TRUE); + + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, message_handler, NULL); + + /* + * Parse the global options. We rearrange the options as + * necessary, in order to pass relevant options through + * to the commands, but also have them take effect globally. + */ + + for (in = 1, out = 1; in < argc; in++, out++) + { + /* The non-option is the command, take it out of the arguments */ + if (argv[in][0] != '-') + { + if (command_name == NULL) + { + command_name = argv[in]; + out--; + continue; + } + } + + argv[out] = argv[in]; + } + + argc = out; + + command = commands; + while (command->name) + { + if (g_strcmp0 (command_name, command->name) == 0) + break; + command++; + } + + if (!command->fn) + { + g_autoptr(GOptionContext) context = + ostree_option_context_new_with_commands (commands); + + /* This will not return for some options (e.g. --version). */ + if (ostree_option_context_parse (context, NULL, &argc, &argv, NULL, NULL, cancellable, &error)) + { + if (command_name == NULL) + { + g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No command specified"); + } + else + { + g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown command '%s'", command_name); + } + } + + ostree_usage (commands, TRUE); + goto out; + } + +#ifndef BUILDOPT_TSAN + prgname = g_strdup_printf ("%s %s", g_get_prgname (), command_name); + g_set_prgname (prgname); +#endif + OstreeCommandInvocation invocation = { .command = command }; + if (!command->fn (argc, argv, &invocation, cancellable, &error)) + goto out; + + success = TRUE; + out: + g_assert (success || error); + + if (error) + { + g_propagate_error (res_error, error); + return 1; + } + return 0; +} + +/* Process a --repo arg; used below, and for the remote builtins */ +static OstreeRepo * +parse_repo_option (GOptionContext *context, + const char *repo_path, + gboolean skip_repo_open, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepo) repo = NULL; + + /* This is a bit of a brutal hack; we set up a mount + * namespace if it appears that we may need it. It'd + * be better to do this more precisely in the future. + */ + gboolean setup_ns = FALSE; + if (!maybe_setup_mount_namespace (&setup_ns, error)) + return FALSE; + if (setup_ns) + { + if (mount ("/sysroot", "/sysroot", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) + return glnx_null_throw_errno_prefix (error, "Remounting /sysroot read-write"); + } + + if (repo_path == NULL) + { + g_autoptr(GError) local_error = NULL; + + repo = ostree_repo_new_default (); + if (!ostree_repo_open (repo, cancellable, &local_error)) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_autofree char *help = NULL; + + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Command requires a --repo argument"); + + help = g_option_context_get_help (context, FALSE, NULL); + g_printerr ("%s", help); + } + else + { + g_propagate_error (error, g_steal_pointer (&local_error)); + } + return NULL; + } + } + else + { + g_autoptr(GFile) repo_file = g_file_new_for_path (repo_path); + + repo = ostree_repo_new (repo_file); + if (!skip_repo_open) + { + if (!ostree_repo_open (repo, cancellable, error)) + return NULL; + } + } + + return g_steal_pointer (&repo); +} + +/* Used by the remote builtins which are special in taking --sysroot or --repo */ +gboolean +ostree_parse_sysroot_or_repo_option (GOptionContext *context, + const char *sysroot_path, + const char *repo_path, + OstreeSysroot **out_sysroot, + OstreeRepo **out_repo, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeSysroot) sysroot = NULL; + g_autoptr(OstreeRepo) repo = NULL; + if (sysroot_path) + { + g_autoptr(GFile) sysroot_file = g_file_new_for_path (sysroot_path); + sysroot = ostree_sysroot_new (sysroot_file); + if (!ostree_sysroot_load (sysroot, cancellable, error)) + return FALSE; + if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) + return FALSE; + } + else + { + repo = parse_repo_option (context, repo_path, FALSE, cancellable, error); + if (!repo) + return FALSE; + } + + ot_transfer_out_value (out_sysroot, &sysroot); + ot_transfer_out_value (out_repo, &repo); + return TRUE; +} + +gboolean +ostree_option_context_parse (GOptionContext *context, + const GOptionEntry *main_entries, + int *argc, + char ***argv, + OstreeCommandInvocation *invocation, + OstreeRepo **out_repo, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepo) repo = NULL; + /* When invocation is NULL, do not fetch repo */ + const OstreeBuiltinFlags flags = invocation ? invocation->command->flags : OSTREE_BUILTIN_FLAG_NO_REPO; + + if (invocation && invocation->command->description != NULL) + { + const char *context_summary = g_option_context_get_summary (context); + + /* If the summary is originally empty, we set the description, but + * for root commands(command with subcommands), we want to prepend + * the description to the existing summary string + */ + if (context_summary == NULL) + g_option_context_set_summary (context, invocation->command->description); + else + { + /* TODO: remove this part once we deduplicate the ostree_option_context_new_with_commands + * function from other root commands( command with subcommands). Because + * we can directly add the summary inside the ostree_option_context_new_with_commands function. + */ + g_autoptr(GString) new_summary_string = g_string_new (context_summary); + + g_string_prepend (new_summary_string, "\n\n"); + g_string_prepend (new_summary_string, invocation->command->description); + + g_option_context_set_summary (context, new_summary_string->str); + } + } + /* Entries are listed in --help output in the order added. We add the + * main entries ourselves so that we can add the --repo entry first. */ + + if (!(flags & OSTREE_BUILTIN_FLAG_NO_REPO)) + g_option_context_add_main_entries (context, repo_entry, NULL); + + if (main_entries != NULL) + g_option_context_add_main_entries (context, main_entries, NULL); + + g_option_context_add_main_entries (context, global_entries, NULL); + + if (!g_option_context_parse (context, argc, argv, error)) + return FALSE; + + /* Filter out the first -- we see; g_option_context_parse() leaves it in */ + int in, out; + gboolean removed_double_dashes = FALSE; + for (in = 1, out = 1; in < *argc; in++, out++) + { + if (g_str_equal ((*argv)[in], "--") && !removed_double_dashes) + { + removed_double_dashes = TRUE; + out--; + continue; + } + + (*argv)[out] = (*argv)[in]; + } + *argc = out; + + if (opt_version) + { + /* This should now be YAML, like `docker version`, so it's both nice to read + * possible to parse */ + g_auto(GStrv) features = g_strsplit (OSTREE_FEATURES, " ", -1); + g_print ("%s:\n", PACKAGE_NAME); + g_print (" Version: '%s'\n", PACKAGE_VERSION); + if (strlen (OSTREE_GITREV) > 0) + g_print (" Git: %s\n", OSTREE_GITREV); +#ifdef BUILDOPT_IS_DEVEL_BUILD + g_print (" DevelBuild: yes\n"); +#endif + g_print (" Features:\n"); + for (char **iter = features; iter && *iter; iter++) + g_print (" - %s\n", *iter); + exit (EXIT_SUCCESS); + } + + if (opt_verbose) + g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, message_handler, NULL); + + if (!(flags & OSTREE_BUILTIN_FLAG_NO_REPO)) + { + repo = parse_repo_option (context, opt_repo, (flags & OSTREE_BUILTIN_FLAG_NO_CHECK) > 0, + cancellable, error); + if (!repo) + return FALSE; + } + + if (out_repo) + *out_repo = g_steal_pointer (&repo); + + return TRUE; +} + +static void +on_sysroot_journal_msg (OstreeSysroot *sysroot, + const char *msg, + void *dummy) +{ + g_print ("%s\n", msg); +} + +gboolean +ostree_admin_option_context_parse (GOptionContext *context, + const GOptionEntry *main_entries, + int *argc, + char ***argv, + OstreeAdminBuiltinFlags flags, + OstreeCommandInvocation *invocation, + OstreeSysroot **out_sysroot, + GCancellable *cancellable, + GError **error) +{ + /* Entries are listed in --help output in the order added. We add the + * main entries ourselves so that we can add the --sysroot entry first. */ + + g_option_context_add_main_entries (context, global_admin_entries, NULL); + + if (!ostree_option_context_parse (context, main_entries, argc, argv, + invocation, NULL, cancellable, error)) + return FALSE; + + if (!opt_print_current_dir && (flags & OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT)) + { + g_assert_null (out_sysroot); + /* Early return if no sysroot is requested */ + return TRUE; + } + + g_autoptr(GFile) sysroot_path = NULL; + if (opt_sysroot != NULL) + sysroot_path = g_file_new_for_path (opt_sysroot); + + g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (sysroot_path); + if (!ostree_sysroot_initialize (sysroot, error)) + return FALSE; + g_signal_connect (sysroot, "journal-msg", G_CALLBACK (on_sysroot_journal_msg), NULL); + + if ((flags & OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED) == 0) + { + /* If we're requested to lock the sysroot, first check if we're operating + * on a booted (not physical) sysroot. Then find out if the /sysroot + * subdir is a read-only mount point, and if so, create a new mount + * namespace and tell the sysroot that we've done so. See the docs for + * ostree_sysroot_set_mount_namespace_in_use(). + * + * This is a conservative approach; we could just always + * unshare() too. + */ + if (ostree_sysroot_is_booted (sysroot)) + { + gboolean setup_ns = FALSE; + if (!maybe_setup_mount_namespace (&setup_ns, error)) + return FALSE; + if (setup_ns) + ostree_sysroot_set_mount_namespace_in_use (sysroot); + } + + /* Released when sysroot is finalized, or on process exit */ + if (!ot_admin_sysroot_lock (sysroot, error)) + return FALSE; + } + + if (!ostree_sysroot_load (sysroot, cancellable, error)) + return FALSE; + + if (flags & OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER) + { + OstreeDeployment *booted = ostree_sysroot_get_booted_deployment (sysroot); + + /* Only require root if we're manipulating a booted sysroot. (Mostly + * useful for the test suite) + */ + if (booted && getuid () != 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, + "You must be root to perform this command"); + return FALSE; + } + } + + if (opt_print_current_dir) + { + g_autoptr(GPtrArray) deployments = NULL; + OstreeDeployment *first_deployment; + g_autoptr(GFile) deployment_file = NULL; + g_autofree char *deployment_path = NULL; + + deployments = ostree_sysroot_get_deployments (sysroot); + if (deployments->len == 0) + return glnx_throw (error, "Unable to find a deployment in sysroot"); + first_deployment = deployments->pdata[0]; + deployment_file = ostree_sysroot_get_deployment_directory (sysroot, first_deployment); + deployment_path = g_file_get_path (deployment_file); + + g_print ("%s\n", deployment_path); + + /* The g_autoptr, g_autofree etc. don't happen when we explicitly + * exit, making valgrind complain about leaks */ + g_clear_object (&sysroot); + g_clear_object (&sysroot_path); + g_clear_object (&deployment_file); + g_clear_pointer (&deployments, g_ptr_array_unref); + g_clear_pointer (&deployment_path, g_free); + exit (EXIT_SUCCESS); + } + + if (out_sysroot) + *out_sysroot = g_steal_pointer (&sysroot); + + return TRUE; +} + +gboolean +ostree_ensure_repo_writable (OstreeRepo *repo, + GError **error) +{ + if (!ostree_repo_is_writable (repo, error)) + return glnx_prefix_error (error, "Cannot write to repository"); + return TRUE; +} + +#ifndef OSTREE_DISABLE_GPGME +void +ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result) +{ + guint n_sigs = ostree_gpg_verify_result_count_all (result); + + /* XXX If we ever add internationalization, use ngettext() here. */ + g_print ("GPG: Verification enabled, found %u signature%s:\n", + n_sigs, n_sigs == 1 ? "" : "s"); + + g_autoptr(GString) buffer = g_string_sized_new (256); + + for (guint ii = 0; ii < n_sigs; ii++) + { + g_string_append_c (buffer, '\n'); + ostree_gpg_verify_result_describe (result, ii, buffer, " ", + OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT); + } + + g_print ("%s", buffer->str); +} +#endif /* OSTREE_DISABLE_GPGME */ + +gboolean +ot_enable_tombstone_commits (OstreeRepo *repo, GError **error) +{ + gboolean tombstone_commits = FALSE; + GKeyFile *config = ostree_repo_get_config (repo); + + tombstone_commits = g_key_file_get_boolean (config, "core", "tombstone-commits", NULL); + /* tombstone_commits is FALSE either if it is not found or it is really set to FALSE in the config file. */ + if (!tombstone_commits) + { + g_key_file_set_boolean (config, "core", "tombstone-commits", TRUE); + if (!ostree_repo_write_config (repo, config, error)) + return FALSE; + } + + return TRUE; +} diff --git a/src/ostree/ot-main.h b/src/ostree/ot-main.h new file mode 100644 index 0000000..b1b994b --- /dev/null +++ b/src/ostree/ot-main.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include "libglnx.h" +#include "ostree.h" + +typedef enum { + OSTREE_BUILTIN_FLAG_NONE = 0, + OSTREE_BUILTIN_FLAG_NO_REPO = 1 << 0, + OSTREE_BUILTIN_FLAG_NO_CHECK = 1 << 1, + OSTREE_BUILTIN_FLAG_HIDDEN = 1 << 2, +} OstreeBuiltinFlags; + +typedef enum { + OSTREE_ADMIN_BUILTIN_FLAG_NONE = 0, + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER = (1 << 0), + OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED = (1 << 1), + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT = (1 << 2), +} OstreeAdminBuiltinFlags; + + +typedef struct OstreeCommandInvocation OstreeCommandInvocation; + +typedef struct { + const char *name; + OstreeBuiltinFlags flags; + gboolean (*fn) (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error); + const char *description; +} OstreeCommand; + +/* This is a similar implementation as + * https://github.com/projectatomic/rpm-ostree/commit/12c34bb2491a07079c911ef26401fee939e5573c. + * + * In the future if we want to add something new we won't need to + * touch every prototype + */ +struct OstreeCommandInvocation { + OstreeCommand *command; +}; + +int ostree_run (int argc, char **argv, OstreeCommand *commands, GError **error); + +int ostree_usage (OstreeCommand *commands, gboolean is_error); + +gboolean ostree_parse_sysroot_or_repo_option (GOptionContext *context, + const char *sysroot_path, + const char *repo_path, + OstreeSysroot **out_sysroot, + OstreeRepo **out_repo, + GCancellable *cancellable, + GError **error); + +gboolean ostree_option_context_parse (GOptionContext *context, + const GOptionEntry *main_entries, + int *argc, char ***argv, + OstreeCommandInvocation *invocation, + OstreeRepo **out_repo, + GCancellable *cancellable, GError **error); + +gboolean ostree_admin_option_context_parse (GOptionContext *context, + const GOptionEntry *main_entries, + int *argc, char ***argv, + OstreeAdminBuiltinFlags flags, + OstreeCommandInvocation *invocation, + OstreeSysroot **out_sysroot, + GCancellable *cancellable, GError **error); + +gboolean ostree_ensure_repo_writable (OstreeRepo *repo, GError **error); + +void ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result); + +gboolean ot_enable_tombstone_commits (OstreeRepo *repo, GError **error); + +/* Copied from rpm-ostree's rpmostree-libbuiltin.h */ +#define TERM_ESCAPE_SEQUENCE(type,seq) \ + static inline const char* ot_get_##type (void) { \ + if (glnx_stdout_is_tty ()) \ + return seq; \ + return ""; \ + } + +TERM_ESCAPE_SEQUENCE(red_start, "\x1b[31m") +TERM_ESCAPE_SEQUENCE(red_end, "\x1b[22m") +TERM_ESCAPE_SEQUENCE(bold_start, "\x1b[1m") +TERM_ESCAPE_SEQUENCE(bold_end, "\x1b[0m") + +#undef TERM_ESCAPE_SEQUENCE diff --git a/src/ostree/ot-remote-builtin-add-cookie.c b/src/ostree/ot-remote-builtin-add-cookie.c new file mode 100644 index 0000000..0b2647f --- /dev/null +++ b/src/ostree/ot-remote-builtin-add-cookie.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * Copyright (C) 2016 Sjoerd Simons + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" + +#include "ot-main.h" +#include "ot-remote-builtins.h" +#include "ostree-repo-private.h" +#include "ot-remote-cookie-util.h" + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { NULL } +}; + +gboolean +ot_remote_builtin_add_cookie (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = g_option_context_new ("NAME DOMAIN PATH COOKIE_NAME VALUE"); + g_autoptr(OstreeRepo) repo = NULL; + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, &repo, cancellable, error)) + return FALSE; + + if (argc < 6) + { + ot_util_usage_error (context, "NAME, DOMAIN, PATH, COOKIE_NAME and VALUE must be specified", error); + return FALSE; + } + + const char *remote_name = argv[1]; + const char *domain = argv[2]; + const char *path = argv[3]; + const char *cookie_name = argv[4]; + const char *value = argv[5]; + g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name); + if (!ot_add_cookie_at (ostree_repo_get_dfd (repo), cookie_file, domain, path, cookie_name, value, error)) + return FALSE; + + return TRUE; +} diff --git a/src/ostree/ot-remote-builtin-add.c b/src/ostree/ot-remote-builtin-add.c new file mode 100644 index 0000000..172625d --- /dev/null +++ b/src/ostree/ot-remote-builtin-add.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" + +#include "ot-main.h" +#include "ot-remote-builtins.h" + +static char **opt_set; +static gboolean opt_no_gpg_verify; +static gboolean opt_no_sign_verify; +static gboolean opt_if_not_exists; +static gboolean opt_force; +static char *opt_gpg_import; +static char **opt_sign_verify; +static char *opt_contenturl; +static char *opt_collection_id; +static char *opt_sysroot; +static char *opt_repo; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { "set", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_set, "Set config option KEY=VALUE for remote", "KEY=VALUE" }, + { "no-gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_no_gpg_verify, "Disable GPG verification", NULL }, + { "no-sign-verify", 0, 0, G_OPTION_ARG_NONE, &opt_no_sign_verify, "Disable signature verification", NULL }, + { "sign-verify", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_sign_verify, "Verify signatures using KEYTYPE=inline:PUBKEY or KEYTYPE=file:/path/to/key", "KEYTYPE=[inline|file]:PUBKEY" }, + { "if-not-exists", 0, 0, G_OPTION_ARG_NONE, &opt_if_not_exists, "Do nothing if the provided remote exists", NULL }, + { "force", 0, 0, G_OPTION_ARG_NONE, &opt_force, "Replace the provided remote if it exists", NULL }, + { "gpg-import", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_import, "Import GPG key from FILE", "FILE" }, + { "contenturl", 0, 0, G_OPTION_ARG_STRING, &opt_contenturl, "Use URL when fetching content", "URL" }, + { "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id, + "Globally unique ID for this repository as an collection of refs for redistribution to other repositories", "COLLECTION-ID" }, + { "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" }, + { "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Use sysroot at PATH (overrides --repo)", "PATH" }, + { NULL } +}; + +static char * +add_verify_opt (GVariantBuilder *builder, + const char *keyspec, + GError **error) +{ + g_auto(GStrv) parts = g_strsplit (keyspec, "=", 2); + g_assert (parts && *parts); + const char *keytype = parts[0]; + if (!parts[1]) + return glnx_null_throw (error, "Failed to parse KEYTYPE=[inline|file]:DATA in %s", keyspec); + + g_autoptr(OstreeSign) sign = ostree_sign_get_by_name (keytype, error); + if (!sign) + return NULL; + + const char *rest = parts[1]; + g_assert (!parts[2]); + g_auto(GStrv) keyparts = g_strsplit (rest, ":", 2); + g_assert (keyparts && *keyparts); + const char *keyref = keyparts[0]; + g_assert (keyref); + g_autofree char *optname = NULL; + if (g_str_equal (keyref, "inline")) + optname = g_strdup_printf ("verification-%s-key", keytype); + else if (g_str_equal (keyref, "file")) + optname = g_strdup_printf ("verification-%s-file", keytype); + else + return glnx_null_throw (error, "Invalid key reference %s, expected inline|file", keyref); + + g_assert (keyparts[1] && !keyparts[2]); + g_variant_builder_add (builder, "{s@v}", + optname, + g_variant_new_variant (g_variant_new_string (keyparts[1]))); + return g_strdup (ostree_sign_get_name (sign)); +} + +gboolean +ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GString) sign_verify = NULL; + const char *remote_name; + const char *remote_url; + char **iter; + g_autoptr(GVariantBuilder) optbuilder = NULL; + g_autoptr(GVariant) options = NULL; + gboolean ret = FALSE; + + context = g_option_context_new ("NAME [metalink=|mirrorlist=]URL [BRANCH...]"); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, NULL, cancellable, error)) + goto out; + + if (!ostree_parse_sysroot_or_repo_option (context, opt_sysroot, opt_repo, + &sysroot, &repo, + cancellable, error)) + goto out; + + if (argc < 3) + { + ot_util_usage_error (context, "NAME and URL must be specified", error); + goto out; + } + + if (opt_if_not_exists && opt_force) + { + ot_util_usage_error (context, + "Can only specify one of --if-not-exists and --force", + error); + goto out; + } + + remote_name = argv[1]; + remote_url = argv[2]; + + optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + + if (argc > 3) + { + g_autoptr(GPtrArray) branchesp = g_ptr_array_new (); + int i; + + for (i = 3; i < argc; i++) + g_ptr_array_add (branchesp, argv[i]); + g_ptr_array_add (branchesp, NULL); + + g_variant_builder_add (optbuilder, "{s@v}", + "branches", + g_variant_new_variant (g_variant_new_strv ((const char*const*)branchesp->pdata, -1))); + } + + /* We could just make users use --set instead for this since it's a string, + * but e.g. when mirrorlist support is added, it'll be kinda awkward to type: + * --set=contenturl=mirrorlist=... */ + + if (opt_contenturl != NULL) + g_variant_builder_add (optbuilder, "{s@v}", + "contenturl", g_variant_new_variant (g_variant_new_string (opt_contenturl))); + + for (iter = opt_set; iter && *iter; iter++) + { + const char *keyvalue = *iter; + g_autofree char *subkey = NULL; + g_autofree char *subvalue = NULL; + + if (!ot_parse_keyvalue (keyvalue, &subkey, &subvalue, error)) + goto out; + + g_variant_builder_add (optbuilder, "{s@v}", + subkey, g_variant_new_variant (g_variant_new_string (subvalue))); + } + +#ifndef OSTREE_DISABLE_GPGME + /* No signature verification implies no verification for GPG signature as well */ + if (opt_no_gpg_verify || opt_no_sign_verify) + g_variant_builder_add (optbuilder, "{s@v}", + "gpg-verify", + g_variant_new_variant (g_variant_new_boolean (FALSE))); +#endif /* OSTREE_DISABLE_GPGME */ + + if (opt_no_sign_verify) + { + if (opt_sign_verify) + return glnx_throw (error, "Cannot specify both --sign-verify and --no-sign-verify"); + g_variant_builder_add (optbuilder, "{s@v}", + "sign-verify", + g_variant_new_variant (g_variant_new_boolean (FALSE))); + } + + for (char **iter = opt_sign_verify; iter && *iter; iter++) + { + const char *keyspec = *iter; + g_autofree char *signname = add_verify_opt (optbuilder, keyspec, error); + if (!signname) + return FALSE; + if (!sign_verify) + { + sign_verify = g_string_new (signname); + } + else + { + g_string_append_c (sign_verify, ','); + g_string_append (sign_verify, signname); + } + } + if (sign_verify != NULL) + g_variant_builder_add (optbuilder, "{s@v}", + "sign-verify", + g_variant_new_variant (g_variant_new_string (sign_verify->str))); + + if (opt_collection_id != NULL) + g_variant_builder_add (optbuilder, "{s@v}", "collection-id", + g_variant_new_variant (g_variant_new_take_string (g_steal_pointer (&opt_collection_id)))); + + options = g_variant_ref_sink (g_variant_builder_end (optbuilder)); + + OstreeRepoRemoteChange changeop; + if (opt_if_not_exists) + changeop = OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS; + else if (opt_force) + changeop = OSTREE_REPO_REMOTE_CHANGE_REPLACE; + else + changeop = OSTREE_REPO_REMOTE_CHANGE_ADD; + if (!ostree_repo_remote_change (repo, NULL, changeop, + remote_name, remote_url, + options, + cancellable, error)) + goto out; + +#ifndef OSTREE_DISABLE_GPGME + /* This is just a convenience option and is not as flexible as the full + * "ostree remote gpg-import" command. It imports all keys from a file, + * which is likely the most common case. + * + * XXX Not sure this interacts well with if-not-exists since we don't + * know whether the remote already existed. We import regardless. */ + if (opt_gpg_import != NULL) + { + g_autoptr(GFile) file = NULL; + g_autoptr(GInputStream) input_stream = NULL; + guint imported = 0; + + file = g_file_new_for_path (opt_gpg_import); + input_stream = (GInputStream *) g_file_read (file, cancellable, error); + + if (input_stream == NULL) + goto out; + + if (!ostree_repo_remote_gpg_import (repo, remote_name, input_stream, + NULL, &imported, cancellable, error)) + goto out; + + /* XXX If we ever add internationalization, use ngettext() here. */ + g_print ("Imported %u GPG key%s to remote \"%s\"\n", + imported, (imported == 1) ? "" : "s", remote_name); + } +#endif /* OSTREE_DISABLE_GPGME */ + + ret = TRUE; + out: + return ret; +} diff --git a/src/ostree/ot-remote-builtin-delete-cookie.c b/src/ostree/ot-remote-builtin-delete-cookie.c new file mode 100644 index 0000000..441e450 --- /dev/null +++ b/src/ostree/ot-remote-builtin-delete-cookie.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * Copyright (C) 2016 Sjoerd Simons + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" +#include + +#include "ot-main.h" +#include "ot-remote-builtins.h" +#include "ostree-repo-private.h" +#include "ot-remote-cookie-util.h" + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { NULL } +}; + +gboolean +ot_remote_builtin_delete_cookie (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GOptionContext) context = g_option_context_new ("NAME DOMAIN PATH COOKIE_NAME"); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, &repo, cancellable, error)) + return FALSE; + + if (argc < 5) + { + ot_util_usage_error (context, "NAME, DOMAIN, PATH and COOKIE_NAME must be specified", error); + return FALSE; + } + + const char *remote_name = argv[1]; + const char *domain = argv[2]; + const char *path = argv[3]; + const char *cookie_name = argv[4]; + g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name); + if (!ot_delete_cookie_at (ostree_repo_get_dfd (repo), cookie_file, domain, path, cookie_name, error)) + return FALSE; + + return TRUE; +} diff --git a/src/ostree/ot-remote-builtin-delete.c b/src/ostree/ot-remote-builtin-delete.c new file mode 100644 index 0000000..ff38b0d --- /dev/null +++ b/src/ostree/ot-remote-builtin-delete.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" + +#include "ot-main.h" +#include "ot-remote-builtins.h" + +static gboolean opt_if_exists = FALSE; +static char *opt_sysroot; +static char *opt_repo; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { "if-exists", 0, 0, G_OPTION_ARG_NONE, &opt_if_exists, "Do nothing if the provided remote does not exist", NULL }, + { "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" }, + { "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Use sysroot at PATH (overrides --repo)", "PATH" }, + { NULL } +}; + +gboolean +ot_remote_builtin_delete (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + + g_autoptr(GOptionContext) context = g_option_context_new ("NAME"); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, NULL, cancellable, error)) + return FALSE; + + g_autoptr(OstreeSysroot) sysroot = NULL; + g_autoptr(OstreeRepo) repo = NULL; + if (!ostree_parse_sysroot_or_repo_option (context, opt_sysroot, opt_repo, + &sysroot, &repo, + cancellable, error)) + return FALSE; + + if (argc < 2) + { + ot_util_usage_error (context, "NAME must be specified", error); + return FALSE; + } + + const char *remote_name = argv[1]; + + if (!ostree_repo_remote_change (repo, NULL, + opt_if_exists ? OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS : + OSTREE_REPO_REMOTE_CHANGE_DELETE, + remote_name, NULL, NULL, + cancellable, error)) + return FALSE; + + return TRUE; +} diff --git a/src/ostree/ot-remote-builtin-gpg-import.c b/src/ostree/ot-remote-builtin-gpg-import.c new file mode 100644 index 0000000..83bb19d --- /dev/null +++ b/src/ostree/ot-remote-builtin-gpg-import.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include "otutil.h" + +#include "ot-main.h" +#include "ot-remote-builtins.h" + +/* XXX This belongs in libotutil. */ +#include "ostree-chain-input-stream.h" + +static gboolean opt_stdin; +static char **opt_keyrings; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { "keyring", 'k', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_keyrings, "Import keys from a keyring file (repeatable)", "FILE" }, + { "stdin", 0, 0, G_OPTION_ARG_NONE, &opt_stdin, "Import keys from standard input", NULL }, + { NULL } +}; + +static gboolean +open_source_stream (GInputStream **out_source_stream, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GInputStream) source_stream = NULL; + guint n_keyrings = 0; + gboolean ret = FALSE; + + if (opt_keyrings != NULL) + n_keyrings = g_strv_length (opt_keyrings); + + if (opt_stdin) + { + source_stream = g_unix_input_stream_new (STDIN_FILENO, FALSE); + } + else + { + g_autoptr(GPtrArray) streams = NULL; + guint ii; + + streams = g_ptr_array_new_with_free_func (g_object_unref); + + for (ii = 0; ii < n_keyrings; ii++) + { + g_autoptr(GFile) file = NULL; + GFileInputStream *input_stream = NULL; + + file = g_file_new_for_path (opt_keyrings[ii]); + input_stream = g_file_read (file, cancellable, error); + + if (input_stream == NULL) + goto out; + + /* Takes ownership. */ + g_ptr_array_add (streams, input_stream); + } + + /* Chain together all the --keyring options as one long stream. */ + source_stream = (GInputStream *) ostree_chain_input_stream_new (streams); + } + + *out_source_stream = g_steal_pointer (&source_stream); + + ret = TRUE; + +out: + return ret; +} + +gboolean +ot_remote_builtin_gpg_import (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GInputStream) source_stream = NULL; + const char *remote_name; + const char * const *key_ids; + guint imported = 0; + gboolean ret = FALSE; + + context = g_option_context_new ("NAME [KEY-ID...]"); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + ot_util_usage_error (context, "NAME must be specified", error); + goto out; + } + + if (opt_stdin && opt_keyrings != NULL) + { + ot_util_usage_error (context, "--keyring and --stdin are mutually exclusive", error); + goto out; + } + + remote_name = argv[1]; + key_ids = (argc > 2) ? (const char * const *) argv + 2 : NULL; + + if (!open_source_stream (&source_stream, cancellable, error)) + goto out; + + if (!ostree_repo_remote_gpg_import (repo, remote_name, source_stream, + key_ids, &imported, cancellable, error)) + goto out; + + /* XXX If we ever add internationalization, use ngettext() here. */ + g_print ("Imported %u GPG key%s to remote \"%s\"\n", + imported, (imported == 1) ? "" : "s", remote_name); + + ret = TRUE; + + out: + return ret; +} diff --git a/src/ostree/ot-remote-builtin-list-cookies.c b/src/ostree/ot-remote-builtin-list-cookies.c new file mode 100644 index 0000000..549deee --- /dev/null +++ b/src/ostree/ot-remote-builtin-list-cookies.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * Copyright (C) 2016 Sjoerd Simons + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" + +#include "ot-main.h" +#include "ot-remote-builtins.h" +#include "ostree-repo-private.h" +#include "ot-remote-cookie-util.h" + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { NULL } +}; + +gboolean +ot_remote_builtin_list_cookies (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GOptionContext) context = g_option_context_new ("NAME"); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, &repo, cancellable, error)) + return FALSE; + + if (argc < 2) + { + ot_util_usage_error (context, "NAME must be specified", error); + return FALSE; + } + + const char *remote_name = argv[1]; + g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name); + if (!ot_list_cookies_at (ostree_repo_get_dfd (repo), cookie_file, error)) + return FALSE; + + return TRUE; +} diff --git a/src/ostree/ot-remote-builtin-list.c b/src/ostree/ot-remote-builtin-list.c new file mode 100644 index 0000000..51c78a1 --- /dev/null +++ b/src/ostree/ot-remote-builtin-list.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-main.h" +#include "ot-remote-builtins.h" + +static gboolean opt_show_urls; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { "show-urls", 'u', 0, G_OPTION_ARG_NONE, &opt_show_urls, "Show remote URLs in list", NULL }, + { NULL } +}; + +gboolean +ot_remote_builtin_list (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_auto(GStrv) remotes = NULL; + guint ii, n_remotes = 0; + gboolean ret = FALSE; + + context = g_option_context_new (""); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, &repo, cancellable, error)) + goto out; + + remotes = ostree_repo_remote_list (repo, &n_remotes); + + if (opt_show_urls) + { + int max_length = 0; + + for (ii = 0; ii < n_remotes; ii++) + max_length = MAX (max_length, strlen (remotes[ii])); + + for (ii = 0; ii < n_remotes; ii++) + { + g_autofree char *remote_url = NULL; + + if (!ostree_repo_remote_get_url (repo, remotes[ii], &remote_url, error)) + goto out; + + g_print ("%-*s %s\n", max_length, remotes[ii], remote_url); + } + } + else + { + for (ii = 0; ii < n_remotes; ii++) + g_print ("%s\n", remotes[ii]); + } + + ret = TRUE; + + out: + return ret; +} diff --git a/src/ostree/ot-remote-builtin-refs.c b/src/ostree/ot-remote-builtin-refs.c new file mode 100644 index 0000000..e4c1d10 --- /dev/null +++ b/src/ostree/ot-remote-builtin-refs.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" + +#include "ot-main.h" +#include "ot-remote-builtins.h" + +static char* opt_cache_dir; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, + { NULL } +}; + +gboolean +ot_remote_builtin_refs (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + const char *remote_name; + gboolean ret = FALSE; + g_autoptr(GHashTable) refs = NULL; + + context = g_option_context_new ("NAME"); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + ot_util_usage_error (context, "NAME must be specified", error); + goto out; + } + + if (opt_cache_dir) + { + if (!ostree_repo_set_cache_dir (repo, AT_FDCWD, opt_cache_dir, cancellable, error)) + goto out; + } + + remote_name = argv[1]; + + if (!ostree_repo_remote_list_refs (repo, remote_name, &refs, cancellable, error)) + goto out; + else + { + g_autoptr(GList) ordered_keys = NULL; + GList *iter = NULL; + + ordered_keys = g_hash_table_get_keys (refs); + ordered_keys = g_list_sort (ordered_keys, (GCompareFunc) strcmp); + + for (iter = ordered_keys; iter; iter = iter->next) + { + g_print ("%s:%s\n", remote_name, (const char *) iter->data); + } + } + + ret = TRUE; +out: + return ret; +} diff --git a/src/ostree/ot-remote-builtin-show-url.c b/src/ostree/ot-remote-builtin-show-url.c new file mode 100644 index 0000000..289c744 --- /dev/null +++ b/src/ostree/ot-remote-builtin-show-url.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" + +#include "ot-main.h" +#include "ot-remote-builtins.h" + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { NULL } +}; + +gboolean +ot_remote_builtin_show_url (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + const char *remote_name; + g_autofree char *remote_url = NULL; + gboolean ret = FALSE; + + context = g_option_context_new ("NAME"); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + ot_util_usage_error (context, "NAME must be specified", error); + goto out; + } + + remote_name = argv[1]; + + if (ostree_repo_remote_get_url (repo, remote_name, &remote_url, error)) + { + g_print ("%s\n", remote_url); + ret = TRUE; + } + + out: + return ret; +} diff --git a/src/ostree/ot-remote-builtin-summary.c b/src/ostree/ot-remote-builtin-summary.c new file mode 100644 index 0000000..bd4d026 --- /dev/null +++ b/src/ostree/ot-remote-builtin-summary.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "otutil.h" + +#include "ot-main.h" +#include "ot-dump.h" +#include "ot-remote-builtins.h" + +static gboolean opt_raw; + +static char* opt_cache_dir; + +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + +static GOptionEntry option_entries[] = { + { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, + { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data", NULL }, + { NULL } +}; + +gboolean +ot_remote_builtin_summary (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) +{ + g_autoptr(GOptionContext) context = NULL; + g_autoptr(OstreeRepo) repo = NULL; + const char *remote_name; + g_autoptr(GBytes) summary_bytes = NULL; + g_autoptr(GBytes) signature_bytes = NULL; + OstreeDumpFlags flags = OSTREE_DUMP_NONE; +#ifndef OSTREE_DISABLE_GPGME + gboolean gpg_verify_summary; +#endif + gboolean ret = FALSE; + + context = g_option_context_new ("NAME"); + + if (!ostree_option_context_parse (context, option_entries, &argc, &argv, + invocation, &repo, cancellable, error)) + goto out; + + if (argc < 2) + { + ot_util_usage_error (context, "NAME must be specified", error); + goto out; + } + + remote_name = argv[1]; + + if (opt_cache_dir) + { + if (!ostree_repo_set_cache_dir (repo, AT_FDCWD, opt_cache_dir, cancellable, error)) + goto out; + } + + if (opt_raw) + flags |= OSTREE_DUMP_RAW; + + if (!ostree_repo_remote_fetch_summary (repo, remote_name, + &summary_bytes, + &signature_bytes, + cancellable, error)) + goto out; + + if (summary_bytes == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Remote server has no summary file"); + goto out; + } + + ot_dump_summary_bytes (summary_bytes, flags); + +#ifndef OSTREE_DISABLE_GPGME + if (!ostree_repo_remote_get_gpg_verify_summary (repo, remote_name, + &gpg_verify_summary, + error)) + goto out; + + if (!gpg_verify_summary) + g_clear_pointer (&signature_bytes, g_bytes_unref); + + /* XXX Note we don't show signatures for "--raw". My intuition is + * if someone needs to see or parse raw summary data, including + * signatures in the output would probably just interfere. + * If there's demand for it I suppose we could introduce a new + * option for raw signature data like "--raw-signatures". */ + if (signature_bytes != NULL && !opt_raw) + { + g_autoptr(OstreeGpgVerifyResult) result = NULL; + + /* The actual signed summary verification happens above in + * ostree_repo_remote_fetch_summary(). Here we just parse + * the signatures again for the purpose of printing. */ + result = ostree_repo_verify_summary (repo, + remote_name, + summary_bytes, + signature_bytes, + cancellable, + error); + if (result == NULL) + goto out; + + g_print ("\n"); + ostree_print_gpg_verify_result (result); + } +#endif /* OSTREE_DISABLE_GPGME */ + + ret = TRUE; +out: + return ret; +} diff --git a/src/ostree/ot-remote-builtins.h b/src/ostree/ot-remote-builtins.h new file mode 100644 index 0000000..71b2365 --- /dev/null +++ b/src/ostree/ot-remote-builtins.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define BUILTINPROTO(name) gboolean ot_remote_builtin_ ## name (int argc, char **argv, \ + OstreeCommandInvocation *invocation, \ + GCancellable *cancellable, GError **error) + +BUILTINPROTO(add); +BUILTINPROTO(delete); +BUILTINPROTO(gpg_import); +BUILTINPROTO(list); +#ifdef HAVE_LIBCURL_OR_LIBSOUP +BUILTINPROTO(add_cookie); +BUILTINPROTO(list_cookies); +BUILTINPROTO(delete_cookie); +#endif +BUILTINPROTO(show_url); +BUILTINPROTO(refs); +BUILTINPROTO(summary); + +#undef BUILTINPROTO + +G_END_DECLS diff --git a/src/ostree/ot-remote-cookie-util.c b/src/ostree/ot-remote-cookie-util.c new file mode 100644 index 0000000..f65a4b6 --- /dev/null +++ b/src/ostree/ot-remote-cookie-util.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * Copyright (C) 2016 Sjoerd Simons + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ot-remote-cookie-util.h" + +#include "otutil.h" +#include "ot-main.h" +#include "ot-remote-builtins.h" +#include "ostree-repo-private.h" + +typedef struct OtCookieParser OtCookieParser; +struct OtCookieParser { + char *buf; + char *iter; + + char *line; + char *domain; + char *flag; + char *path; + char *secure; + long long unsigned int expiration; + char *name; + char *value; +}; +void ot_cookie_parser_free (OtCookieParser *parser); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtCookieParser, ot_cookie_parser_free) + +gboolean +ot_parse_cookies_at (int dfd, const char *path, + OtCookieParser **out_parser, + GCancellable *cancellable, + GError **error); +gboolean +ot_parse_cookies_next (OtCookieParser *parser); + +static void +ot_cookie_parser_clear (OtCookieParser *parser) +{ + g_clear_pointer (&parser->domain, (GDestroyNotify)g_free); + g_clear_pointer (&parser->flag, (GDestroyNotify)g_free); + g_clear_pointer (&parser->path, (GDestroyNotify)g_free); + g_clear_pointer (&parser->secure, (GDestroyNotify)g_free); + g_clear_pointer (&parser->name, (GDestroyNotify)g_free); + g_clear_pointer (&parser->value, (GDestroyNotify)g_free); +} + +void +ot_cookie_parser_free (OtCookieParser *parser) +{ + ot_cookie_parser_clear (parser); + g_free (parser->buf); + g_free (parser); +} + +gboolean +ot_parse_cookies_at (int dfd, const char *path, + OtCookieParser **out_parser, + GCancellable *cancellable, + GError **error) +{ + OtCookieParser *parser; + g_autofree char *cookies_content = NULL; + glnx_autofd int infd = -1; + + infd = openat (dfd, path, O_RDONLY | O_CLOEXEC); + if (infd < 0) + { + if (errno != ENOENT) + { + glnx_set_error_from_errno (error); + return FALSE; + } + } + else + { + cookies_content = glnx_fd_readall_utf8 (infd, NULL, cancellable, error); + if (!cookies_content) + return FALSE; + } + + parser = *out_parser = g_new0 (OtCookieParser, 1); + parser->buf = g_steal_pointer (&cookies_content); + parser->iter = parser->buf; + return TRUE; +} + +gboolean +ot_parse_cookies_next (OtCookieParser *parser) +{ + while (parser->iter) + { + char *iter = parser->iter; + char *next = strchr (iter, '\n'); + + if (next) + { + *next = '\0'; + parser->iter = next + 1; + } + else + parser->iter = NULL; + + ot_cookie_parser_clear (parser); + if (sscanf (iter, "%ms\t%ms\t%ms\t%ms\t%llu\t%ms\t%ms", + &parser->domain, + &parser->flag, + &parser->path, + &parser->secure, + &parser->expiration, + &parser->name, + &parser->value) != 7) + continue; + + parser->line = iter; + return TRUE; + } + + return FALSE; +} + +gboolean +ot_add_cookie_at (int dfd, const char *jar_path, + const char *domain, const char *path, + const char *name, const char *value, + GError **error) +{ + glnx_autofd int fd = openat (dfd, jar_path, O_WRONLY | O_APPEND | O_CREAT, 0644); + if (fd < 0) + return glnx_throw_errno_prefix (error, "open(%s)", jar_path); + + g_autoptr(GDateTime) now = g_date_time_new_now_utc (); + g_autoptr(GDateTime) expires = g_date_time_add_years (now, 25); + + /* Adapted from soup-cookie-jar-text.c:write_cookie() */ + g_autofree char *buf = g_strdup_printf ("%s\t%s\t%s\t%s\t%llu\t%s\t%s\n", + domain, + *domain == '.' ? "TRUE" : "FALSE", + path, + "FALSE", + (long long unsigned)g_date_time_to_unix (expires), + name, + value); + if (glnx_loop_write (fd, buf, strlen (buf)) < 0) + return glnx_throw_errno_prefix (error, "write"); + return TRUE; +} + +gboolean +ot_delete_cookie_at (int dfd, const char *jar_path, + const char *domain, const char *path, + const char *name, + GError **error) +{ + gboolean found = FALSE; + g_auto(GLnxTmpfile) tmpf = { 0, }; + g_autoptr(OtCookieParser) parser = NULL; + + if (!ot_parse_cookies_at (dfd, jar_path, &parser, NULL, error)) + return FALSE; + + g_assert (!strchr (jar_path, '/')); + if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_WRONLY | O_CLOEXEC, + &tmpf, error)) + return FALSE; + + while (ot_parse_cookies_next (parser)) + { + if (strcmp (domain, parser->domain) == 0 && + strcmp (path, parser->path) == 0 && + strcmp (name, parser->name) == 0) + { + found = TRUE; + /* Match, skip writing this one */ + continue; + } + + if (glnx_loop_write (tmpf.fd, parser->line, strlen (parser->line)) < 0 || + glnx_loop_write (tmpf.fd, "\n", 1) < 0) + return glnx_throw_errno_prefix (error, "write"); + } + + if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE, + dfd, jar_path, + error)) + return FALSE; + + if (!found) + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cookie not found in jar"); + + return TRUE; +} + + +gboolean +ot_list_cookies_at (int dfd, const char *jar_path, GError **error) +{ + g_autoptr(OtCookieParser) parser = NULL; + + if (!ot_parse_cookies_at (AT_FDCWD, jar_path, &parser, NULL, error)) + return FALSE; + + while (ot_parse_cookies_next (parser)) + { + g_autoptr(GDateTime) expires = g_date_time_new_from_unix_utc (parser->expiration); + g_autofree char *expires_str = NULL; + + if (expires != NULL) + expires_str = g_date_time_format (expires, "%Y-%m-%d %H:%M:%S +0000"); + + g_print ("--\n"); + g_print ("Domain: %s\n", parser->domain); + g_print ("Path: %s\n", parser->path); + g_print ("Name: %s\n", parser->name); + g_print ("Secure: %s\n", parser->secure); + if (expires_str != NULL) + g_print ("Expires: %s\n", expires_str); + g_print ("Value: %s\n", parser->value); + } + + return TRUE; +} diff --git a/src/ostree/ot-remote-cookie-util.h b/src/ostree/ot-remote-cookie-util.h new file mode 100644 index 0000000..a14f9d0 --- /dev/null +++ b/src/ostree/ot-remote-cookie-util.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "libglnx.h" + +G_BEGIN_DECLS + +gboolean +ot_add_cookie_at (int dfd, const char *jar_path, + const char *domain, const char *path, + const char *name, const char *value, + GError **error); + +gboolean +ot_delete_cookie_at (int dfd, const char *jar_path, + const char *domain, const char *path, + const char *name, + GError **error); + +gboolean +ot_list_cookies_at (int dfd, const char *jar_path, GError **error); + +G_END_DECLS diff --git a/src/ostree/parse-datetime.h b/src/ostree/parse-datetime.h new file mode 100644 index 0000000..6973758 --- /dev/null +++ b/src/ostree/parse-datetime.h @@ -0,0 +1,22 @@ +/* Parse a string into an internal time stamp. + + Copyright (C) 1995, 1997-1998, 2003-2004, 2007, 2009-2015 Free Software + Foundation, Inc. + + 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include + +bool parse_datetime (struct timespec *, char const *, struct timespec const *); diff --git a/src/ostree/parse-datetime.y b/src/ostree/parse-datetime.y new file mode 100644 index 0000000..e1ce305 --- /dev/null +++ b/src/ostree/parse-datetime.y @@ -0,0 +1,1604 @@ +%{ +/* Parse a string into an internal time stamp. + + Copyright (C) 1999-2000, 2002-2015 Free Software Foundation, Inc. + + 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Originally written by Steven M. Bellovin while + at the University of North Carolina at Chapel Hill. Later tweaked by + a couple of people on Usenet. Completely overhauled by Rich $alz + and Jim Berets in August, 1990. + + Modified by Paul Eggert in August 1999 to do + the right thing about local DST. Also modified by Paul Eggert + in February 2004 to support + nanosecond-resolution time stamps, and in October 2004 to support + TZ strings in dates. */ + +/* FIXME: Check for arithmetic overflow in all cases, not just + some of them. */ + + +#include "config.h" +#include "parse-datetime.h" +#include +#include +#include +#include +#include +#include + +/* There's no need to extend the stack, so there's no need to involve + alloca. */ +#define YYSTACK_USE_ALLOCA 0 + +static char * +xmemdup (void const *p, size_t s) +{ + char *result = g_malloc (s); + memcpy (result, p, s); + return result; +} + +static void +gettime (struct timespec *ts) + { +#ifdef HAVE_NANOTIME + nanotime (ts); +#else + +# if defined(CLOCK_REALTIME) && defined(HAVE_CLOCK_GETTIME) + if (clock_gettime (CLOCK_REALTIME, ts) == 0) + return; +# endif + + { + struct timeval tv; + gettimeofday (&tv, NULL); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + } + +#endif + } + +/* Tell Bison how much stack space is needed. 20 should be plenty for + this grammar, which is not right recursive. Beware setting it too + high, since that might cause problems on machines whose + implementations have lame stack-overflow checking. */ +#define YYMAXDEPTH 20 +#define YYINITDEPTH YYMAXDEPTH + +/* Since the code of parse-datetime.y is not included in the Emacs executable + itself, there is no need to #define static in this file. Even if + the code were included in the Emacs executable, it probably + wouldn't do any harm to #undef it here; this will only cause + problems if we try to write to a static variable, which I don't + think this code needs to do. */ +#ifdef emacs +# undef static +#endif + +#include +#include +#include +#include + + +/* Bison's skeleton tests _STDLIB_H, while some stdlib.h headers + use _STDLIB_H_ as witness. Map the latter to the one bison uses. */ +/* FIXME: this is temporary. Remove when we have a mechanism to ensure + that the version we're using is fixed, too. */ +#ifdef _STDLIB_H_ +# undef _STDLIB_H +# define _STDLIB_H 1 +#endif + +/* ISDIGIT differs from isdigit, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char + or EOF. + - It's typically faster. + POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to + isdigit unless it's important to use the locale's definition + of "digit" even when the host does not conform to POSIX. */ +#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9) + +/* Shift A right by B bits portably, by dividing A by 2**B and + truncating towards minus infinity. A and B should be free of side + effects, and B should be in the range 0 <= B <= INT_BITS - 2, where + INT_BITS is the number of useful bits in an int. GNU code can + assume that INT_BITS is at least 32. + + ISO C99 says that A >> B is implementation-defined if A < 0. Some + implementations (e.g., UNICOS 9.0 on a Cray Y-MP EL) don't shift + right in the usual way when A < 0, so SHR falls back on division if + ordinary A >> B doesn't seem to be the usual signed shift. */ +#define SHR(a, b) \ + (-1 >> 1 == -1 \ + ? (a) >> (b) \ + : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0)) + +#define EPOCH_YEAR 1970 +#define TM_YEAR_BASE 1900 + +#define HOUR(x) ((x) * 60) + +/* Convert a possibly-signed character to an unsigned character. This is + a bit safer than casting to unsigned char, since it catches some type + errors that the cast doesn't. */ +static unsigned char to_uchar (char ch) { return ch; } + +/* FIXME: It also assumes that signed integer overflow silently wraps around, + but this is not true any more with recent versions of GCC 4. */ + +/* An integer value, and the number of digits in its textual + representation. */ +typedef struct +{ + bool negative; + long int value; + size_t digits; +} textint; + +/* An entry in the lexical lookup table. */ +typedef struct +{ + char const *name; + int type; + int value; +} table; + +/* Meridian: am, pm, or 24-hour style. */ +enum { MERam, MERpm, MER24 }; + +enum { BILLION = 1000000000, LOG10_BILLION = 9 }; + +/* Relative times. */ +typedef struct +{ + /* Relative year, month, day, hour, minutes, seconds, and nanoseconds. */ + long int year; + long int month; + long int day; + long int hour; + long int minutes; + intmax_t seconds; + int ns; +} relative_time; + +#define RELATIVE_TIME_0 ((relative_time) { 0, 0, 0, 0, 0, 0, 0 }) + +/* Information passed to and from the parser. */ +typedef struct +{ + /* The input string remaining to be parsed. */ + const char *input; + + /* N, if this is the Nth Tuesday. */ + long int day_ordinal; + + /* Day of week; Sunday is 0. */ + int day_number; + + /* tm_isdst flag for the local zone. */ + int local_isdst; + + /* Time zone, in minutes east of UTC. */ + long int time_zone; + + /* Style used for time. */ + int meridian; + + /* Gregorian year, month, day, hour, minutes, seconds, and nanoseconds. */ + textint year; + long int month; + long int day; + long int hour; + long int minutes; + struct timespec seconds; /* includes nanoseconds */ + + /* Relative year, month, day, hour, minutes, seconds, and nanoseconds. */ + relative_time rel; + + /* Presence or counts of nonterminals of various flavors parsed so far. */ + bool timespec_seen; + bool rels_seen; + size_t dates_seen; + size_t days_seen; + size_t local_zones_seen; + size_t dsts_seen; + size_t times_seen; + size_t zones_seen; + + /* Table of local time zone abbreviations, terminated by a null entry. */ + table local_time_zone_table[3]; +} parser_control; + +union YYSTYPE; +static int yylex (union YYSTYPE *, parser_control *); +static int yyerror (parser_control const *, char const *); +static long int time_zone_hhmm (parser_control *, textint, long int); + +/* Extract into *PC any date and time info from a string of digits + of the form e.g., YYYYMMDD, YYMMDD, HHMM, HH (and sometimes YYY, + YYYY, ...). */ +static void +digits_to_date_time (parser_control *pc, textint text_int) +{ + if (pc->dates_seen && ! pc->year.digits + && ! pc->rels_seen && (pc->times_seen || 2 < text_int.digits)) + pc->year = text_int; + else + { + if (4 < text_int.digits) + { + pc->dates_seen++; + pc->day = text_int.value % 100; + pc->month = (text_int.value / 100) % 100; + pc->year.value = text_int.value / 10000; + pc->year.digits = text_int.digits - 4; + } + else + { + pc->times_seen++; + if (text_int.digits <= 2) + { + pc->hour = text_int.value; + pc->minutes = 0; + } + else + { + pc->hour = text_int.value / 100; + pc->minutes = text_int.value % 100; + } + pc->seconds.tv_sec = 0; + pc->seconds.tv_nsec = 0; + pc->meridian = MER24; + } + } +} + +/* Increment PC->rel by FACTOR * REL (FACTOR is 1 or -1). */ +static void +apply_relative_time (parser_control *pc, relative_time rel, int factor) +{ + pc->rel.ns += factor * rel.ns; + pc->rel.seconds += factor * rel.seconds; + pc->rel.minutes += factor * rel.minutes; + pc->rel.hour += factor * rel.hour; + pc->rel.day += factor * rel.day; + pc->rel.month += factor * rel.month; + pc->rel.year += factor * rel.year; + pc->rels_seen = true; +} + +/* Set PC-> hour, minutes, seconds and nanoseconds members from arguments. */ +static void +set_hhmmss (parser_control *pc, long int hour, long int minutes, + time_t sec, long int nsec) +{ + pc->hour = hour; + pc->minutes = minutes; + pc->seconds.tv_sec = sec; + pc->seconds.tv_nsec = nsec; +} + +%} + +/* We want a reentrant parser, even if the TZ manipulation and the calls to + localtime and gmtime are not reentrant. */ +%pure-parser +%parse-param { parser_control *pc } +%lex-param { parser_control *pc } + +/* This grammar has 31 shift/reduce conflicts. */ +%expect 31 + +%union +{ + long int intval; + textint textintval; + struct timespec timespec; + relative_time rel; +} + +%token tAGO +%token tDST + +%token tYEAR_UNIT tMONTH_UNIT tHOUR_UNIT tMINUTE_UNIT tSEC_UNIT +%token tDAY_UNIT tDAY_SHIFT + +%token tDAY tDAYZONE tLOCAL_ZONE tMERIDIAN +%token tMONTH tORDINAL tZONE + +%token tSNUMBER tUNUMBER +%token tSDECIMAL_NUMBER tUDECIMAL_NUMBER + +%type o_colon_minutes +%type seconds signed_seconds unsigned_seconds + +%type relunit relunit_snumber dayshift + +%% + +spec: + timespec + | items + ; + +timespec: + '@' seconds + { + pc->seconds = $2; + pc->timespec_seen = true; + } + ; + +items: + /* empty */ + | items item + ; + +item: + datetime + { pc->times_seen++; pc->dates_seen++; } + | time + { pc->times_seen++; } + | local_zone + { pc->local_zones_seen++; } + | zone + { pc->zones_seen++; } + | date + { pc->dates_seen++; } + | day + { pc->days_seen++; } + | rel + | number + | hybrid + ; + +datetime: + iso_8601_datetime + ; + +iso_8601_datetime: + iso_8601_date 'T' iso_8601_time + ; + +time: + tUNUMBER tMERIDIAN + { + set_hhmmss (pc, $1.value, 0, 0, 0); + pc->meridian = $2; + } + | tUNUMBER ':' tUNUMBER tMERIDIAN + { + set_hhmmss (pc, $1.value, $3.value, 0, 0); + pc->meridian = $4; + } + | tUNUMBER ':' tUNUMBER ':' unsigned_seconds tMERIDIAN + { + set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); + pc->meridian = $6; + } + | iso_8601_time + ; + +iso_8601_time: + tUNUMBER zone_offset + { + set_hhmmss (pc, $1.value, 0, 0, 0); + pc->meridian = MER24; + } + | tUNUMBER ':' tUNUMBER o_zone_offset + { + set_hhmmss (pc, $1.value, $3.value, 0, 0); + pc->meridian = MER24; + } + | tUNUMBER ':' tUNUMBER ':' unsigned_seconds o_zone_offset + { + set_hhmmss (pc, $1.value, $3.value, $5.tv_sec, $5.tv_nsec); + pc->meridian = MER24; + } + ; + +o_zone_offset: + /* empty */ + | zone_offset + ; + +zone_offset: + tSNUMBER o_colon_minutes + { + pc->zones_seen++; + pc->time_zone = time_zone_hhmm (pc, $1, $2); + } + ; + +local_zone: + tLOCAL_ZONE + { + pc->local_isdst = $1; + pc->dsts_seen += (0 < $1); + } + | tLOCAL_ZONE tDST + { + pc->local_isdst = 1; + pc->dsts_seen += (0 < $1) + 1; + } + ; + +/* Note 'T' is a special case, as it is used as the separator in ISO + 8601 date and time of day representation. */ +zone: + tZONE + { pc->time_zone = $1; } + | 'T' + { pc->time_zone = HOUR(7); } + | tZONE relunit_snumber + { pc->time_zone = $1; + apply_relative_time (pc, $2, 1); } + | 'T' relunit_snumber + { pc->time_zone = HOUR(7); + apply_relative_time (pc, $2, 1); } + | tZONE tSNUMBER o_colon_minutes + { pc->time_zone = $1 + time_zone_hhmm (pc, $2, $3); } + | tDAYZONE + { pc->time_zone = $1 + 60; } + | tZONE tDST + { pc->time_zone = $1 + 60; } + ; + +day: + tDAY + { + pc->day_ordinal = 0; + pc->day_number = $1; + } + | tDAY ',' + { + pc->day_ordinal = 0; + pc->day_number = $1; + } + | tORDINAL tDAY + { + pc->day_ordinal = $1; + pc->day_number = $2; + } + | tUNUMBER tDAY + { + pc->day_ordinal = $1.value; + pc->day_number = $2; + } + ; + +date: + tUNUMBER '/' tUNUMBER + { + pc->month = $1.value; + pc->day = $3.value; + } + | tUNUMBER '/' tUNUMBER '/' tUNUMBER + { + /* Interpret as YYYY/MM/DD if the first value has 4 or more digits, + otherwise as MM/DD/YY. + The goal in recognizing YYYY/MM/DD is solely to support legacy + machine-generated dates like those in an RCS log listing. If + you want portability, use the ISO 8601 format. */ + if (4 <= $1.digits) + { + pc->year = $1; + pc->month = $3.value; + pc->day = $5.value; + } + else + { + pc->month = $1.value; + pc->day = $3.value; + pc->year = $5; + } + } + | tUNUMBER tMONTH tSNUMBER + { + /* e.g. 17-JUN-1992. */ + pc->day = $1.value; + pc->month = $2; + pc->year.value = -$3.value; + pc->year.digits = $3.digits; + } + | tMONTH tSNUMBER tSNUMBER + { + /* e.g. JUN-17-1992. */ + pc->month = $1; + pc->day = -$2.value; + pc->year.value = -$3.value; + pc->year.digits = $3.digits; + } + | tMONTH tUNUMBER + { + pc->month = $1; + pc->day = $2.value; + } + | tMONTH tUNUMBER ',' tUNUMBER + { + pc->month = $1; + pc->day = $2.value; + pc->year = $4; + } + | tUNUMBER tMONTH + { + pc->day = $1.value; + pc->month = $2; + } + | tUNUMBER tMONTH tUNUMBER + { + pc->day = $1.value; + pc->month = $2; + pc->year = $3; + } + | iso_8601_date + ; + +iso_8601_date: + tUNUMBER tSNUMBER tSNUMBER + { + /* ISO 8601 format. YYYY-MM-DD. */ + pc->year = $1; + pc->month = -$2.value; + pc->day = -$3.value; + } + ; + +rel: + relunit tAGO + { apply_relative_time (pc, $1, $2); } + | relunit + { apply_relative_time (pc, $1, 1); } + | dayshift + { apply_relative_time (pc, $1, 1); } + ; + +relunit: + tORDINAL tYEAR_UNIT + { $$ = RELATIVE_TIME_0; $$.year = $1; } + | tUNUMBER tYEAR_UNIT + { $$ = RELATIVE_TIME_0; $$.year = $1.value; } + | tYEAR_UNIT + { $$ = RELATIVE_TIME_0; $$.year = 1; } + | tORDINAL tMONTH_UNIT + { $$ = RELATIVE_TIME_0; $$.month = $1; } + | tUNUMBER tMONTH_UNIT + { $$ = RELATIVE_TIME_0; $$.month = $1.value; } + | tMONTH_UNIT + { $$ = RELATIVE_TIME_0; $$.month = 1; } + | tORDINAL tDAY_UNIT + { $$ = RELATIVE_TIME_0; $$.day = $1 * $2; } + | tUNUMBER tDAY_UNIT + { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; } + | tDAY_UNIT + { $$ = RELATIVE_TIME_0; $$.day = $1; } + | tORDINAL tHOUR_UNIT + { $$ = RELATIVE_TIME_0; $$.hour = $1; } + | tUNUMBER tHOUR_UNIT + { $$ = RELATIVE_TIME_0; $$.hour = $1.value; } + | tHOUR_UNIT + { $$ = RELATIVE_TIME_0; $$.hour = 1; } + | tORDINAL tMINUTE_UNIT + { $$ = RELATIVE_TIME_0; $$.minutes = $1; } + | tUNUMBER tMINUTE_UNIT + { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; } + | tMINUTE_UNIT + { $$ = RELATIVE_TIME_0; $$.minutes = 1; } + | tORDINAL tSEC_UNIT + { $$ = RELATIVE_TIME_0; $$.seconds = $1; } + | tUNUMBER tSEC_UNIT + { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; } + | tSDECIMAL_NUMBER tSEC_UNIT + { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; } + | tUDECIMAL_NUMBER tSEC_UNIT + { $$ = RELATIVE_TIME_0; $$.seconds = $1.tv_sec; $$.ns = $1.tv_nsec; } + | tSEC_UNIT + { $$ = RELATIVE_TIME_0; $$.seconds = 1; } + | relunit_snumber + ; + +relunit_snumber: + tSNUMBER tYEAR_UNIT + { $$ = RELATIVE_TIME_0; $$.year = $1.value; } + | tSNUMBER tMONTH_UNIT + { $$ = RELATIVE_TIME_0; $$.month = $1.value; } + | tSNUMBER tDAY_UNIT + { $$ = RELATIVE_TIME_0; $$.day = $1.value * $2; } + | tSNUMBER tHOUR_UNIT + { $$ = RELATIVE_TIME_0; $$.hour = $1.value; } + | tSNUMBER tMINUTE_UNIT + { $$ = RELATIVE_TIME_0; $$.minutes = $1.value; } + | tSNUMBER tSEC_UNIT + { $$ = RELATIVE_TIME_0; $$.seconds = $1.value; } + ; + +dayshift: + tDAY_SHIFT + { $$ = RELATIVE_TIME_0; $$.day = $1; } + ; + +seconds: signed_seconds | unsigned_seconds; + +signed_seconds: + tSDECIMAL_NUMBER + | tSNUMBER + { $$.tv_sec = $1.value; $$.tv_nsec = 0; } + ; + +unsigned_seconds: + tUDECIMAL_NUMBER + | tUNUMBER + { $$.tv_sec = $1.value; $$.tv_nsec = 0; } + ; + +number: + tUNUMBER + { digits_to_date_time (pc, $1); } + ; + +hybrid: + tUNUMBER relunit_snumber + { + /* Hybrid all-digit and relative offset, so that we accept e.g., + "YYYYMMDD +N days" as well as "YYYYMMDD N days". */ + digits_to_date_time (pc, $1); + apply_relative_time (pc, $2, 1); + } + ; + +o_colon_minutes: + /* empty */ + { $$ = -1; } + | ':' tUNUMBER + { $$ = $2.value; } + ; + +%% + +static table const meridian_table[] = +{ + { "AM", tMERIDIAN, MERam }, + { "A.M.", tMERIDIAN, MERam }, + { "PM", tMERIDIAN, MERpm }, + { "P.M.", tMERIDIAN, MERpm }, + { NULL, 0, 0 } +}; + +static table const dst_table[] = +{ + { "DST", tDST, 0 } +}; + +static table const month_and_day_table[] = +{ + { "JANUARY", tMONTH, 1 }, + { "FEBRUARY", tMONTH, 2 }, + { "MARCH", tMONTH, 3 }, + { "APRIL", tMONTH, 4 }, + { "MAY", tMONTH, 5 }, + { "JUNE", tMONTH, 6 }, + { "JULY", tMONTH, 7 }, + { "AUGUST", tMONTH, 8 }, + { "SEPTEMBER",tMONTH, 9 }, + { "SEPT", tMONTH, 9 }, + { "OCTOBER", tMONTH, 10 }, + { "NOVEMBER", tMONTH, 11 }, + { "DECEMBER", tMONTH, 12 }, + { "SUNDAY", tDAY, 0 }, + { "MONDAY", tDAY, 1 }, + { "TUESDAY", tDAY, 2 }, + { "TUES", tDAY, 2 }, + { "WEDNESDAY",tDAY, 3 }, + { "WEDNES", tDAY, 3 }, + { "THURSDAY", tDAY, 4 }, + { "THUR", tDAY, 4 }, + { "THURS", tDAY, 4 }, + { "FRIDAY", tDAY, 5 }, + { "SATURDAY", tDAY, 6 }, + { NULL, 0, 0 } +}; + +static table const time_units_table[] = +{ + { "YEAR", tYEAR_UNIT, 1 }, + { "MONTH", tMONTH_UNIT, 1 }, + { "FORTNIGHT",tDAY_UNIT, 14 }, + { "WEEK", tDAY_UNIT, 7 }, + { "DAY", tDAY_UNIT, 1 }, + { "HOUR", tHOUR_UNIT, 1 }, + { "MINUTE", tMINUTE_UNIT, 1 }, + { "MIN", tMINUTE_UNIT, 1 }, + { "SECOND", tSEC_UNIT, 1 }, + { "SEC", tSEC_UNIT, 1 }, + { NULL, 0, 0 } +}; + +/* Assorted relative-time words. */ +static table const relative_time_table[] = +{ + { "TOMORROW", tDAY_SHIFT, 1 }, + { "YESTERDAY",tDAY_SHIFT, -1 }, + { "TODAY", tDAY_SHIFT, 0 }, + { "NOW", tDAY_SHIFT, 0 }, + { "LAST", tORDINAL, -1 }, + { "THIS", tORDINAL, 0 }, + { "NEXT", tORDINAL, 1 }, + { "FIRST", tORDINAL, 1 }, +/*{ "SECOND", tORDINAL, 2 }, */ + { "THIRD", tORDINAL, 3 }, + { "FOURTH", tORDINAL, 4 }, + { "FIFTH", tORDINAL, 5 }, + { "SIXTH", tORDINAL, 6 }, + { "SEVENTH", tORDINAL, 7 }, + { "EIGHTH", tORDINAL, 8 }, + { "NINTH", tORDINAL, 9 }, + { "TENTH", tORDINAL, 10 }, + { "ELEVENTH", tORDINAL, 11 }, + { "TWELFTH", tORDINAL, 12 }, + { "AGO", tAGO, -1 }, + { "HENCE", tAGO, 1 }, + { NULL, 0, 0 } +}; + +/* The universal time zone table. These labels can be used even for + time stamps that would not otherwise be valid, e.g., GMT time + stamps in London during summer. */ +static table const universal_time_zone_table[] = +{ + { "GMT", tZONE, HOUR ( 0) }, /* Greenwich Mean */ + { "UT", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */ + { "UTC", tZONE, HOUR ( 0) }, + { NULL, 0, 0 } +}; + +/* The time zone table. This table is necessarily incomplete, as time + zone abbreviations are ambiguous; e.g. Australians interpret "EST" + as Eastern time in Australia, not as US Eastern Standard Time. + You cannot rely on parse_datetime to handle arbitrary time zone + abbreviations; use numeric abbreviations like "-0500" instead. */ +static table const time_zone_table[] = +{ + { "WET", tZONE, HOUR ( 0) }, /* Western European */ + { "WEST", tDAYZONE, HOUR ( 0) }, /* Western European Summer */ + { "BST", tDAYZONE, HOUR ( 0) }, /* British Summer */ + { "ART", tZONE, -HOUR ( 3) }, /* Argentina */ + { "BRT", tZONE, -HOUR ( 3) }, /* Brazil */ + { "BRST", tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */ + { "NST", tZONE, -(HOUR ( 3) + 30) }, /* Newfoundland Standard */ + { "NDT", tDAYZONE,-(HOUR ( 3) + 30) }, /* Newfoundland Daylight */ + { "AST", tZONE, -HOUR ( 4) }, /* Atlantic Standard */ + { "ADT", tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */ + { "CLT", tZONE, -HOUR ( 4) }, /* Chile */ + { "CLST", tDAYZONE, -HOUR ( 4) }, /* Chile Summer */ + { "EST", tZONE, -HOUR ( 5) }, /* Eastern Standard */ + { "EDT", tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */ + { "CST", tZONE, -HOUR ( 6) }, /* Central Standard */ + { "CDT", tDAYZONE, -HOUR ( 6) }, /* Central Daylight */ + { "MST", tZONE, -HOUR ( 7) }, /* Mountain Standard */ + { "MDT", tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */ + { "PST", tZONE, -HOUR ( 8) }, /* Pacific Standard */ + { "PDT", tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */ + { "AKST", tZONE, -HOUR ( 9) }, /* Alaska Standard */ + { "AKDT", tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */ + { "HST", tZONE, -HOUR (10) }, /* Hawaii Standard */ + { "HAST", tZONE, -HOUR (10) }, /* Hawaii-Aleutian Standard */ + { "HADT", tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */ + { "SST", tZONE, -HOUR (12) }, /* Samoa Standard */ + { "WAT", tZONE, HOUR ( 1) }, /* West Africa */ + { "CET", tZONE, HOUR ( 1) }, /* Central European */ + { "CEST", tDAYZONE, HOUR ( 1) }, /* Central European Summer */ + { "MET", tZONE, HOUR ( 1) }, /* Middle European */ + { "MEZ", tZONE, HOUR ( 1) }, /* Middle European */ + { "MEST", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */ + { "MESZ", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */ + { "EET", tZONE, HOUR ( 2) }, /* Eastern European */ + { "EEST", tDAYZONE, HOUR ( 2) }, /* Eastern European Summer */ + { "CAT", tZONE, HOUR ( 2) }, /* Central Africa */ + { "SAST", tZONE, HOUR ( 2) }, /* South Africa Standard */ + { "EAT", tZONE, HOUR ( 3) }, /* East Africa */ + { "MSK", tZONE, HOUR ( 3) }, /* Moscow */ + { "MSD", tDAYZONE, HOUR ( 3) }, /* Moscow Daylight */ + { "IST", tZONE, (HOUR ( 5) + 30) }, /* India Standard */ + { "SGT", tZONE, HOUR ( 8) }, /* Singapore */ + { "KST", tZONE, HOUR ( 9) }, /* Korea Standard */ + { "JST", tZONE, HOUR ( 9) }, /* Japan Standard */ + { "GST", tZONE, HOUR (10) }, /* Guam Standard */ + { "NZST", tZONE, HOUR (12) }, /* New Zealand Standard */ + { "NZDT", tDAYZONE, HOUR (12) }, /* New Zealand Daylight */ + { NULL, 0, 0 } +}; + +/* Military time zone table. + + Note 'T' is a special case, as it is used as the separator in ISO + 8601 date and time of day representation. */ +static table const military_table[] = +{ + { "A", tZONE, -HOUR ( 1) }, + { "B", tZONE, -HOUR ( 2) }, + { "C", tZONE, -HOUR ( 3) }, + { "D", tZONE, -HOUR ( 4) }, + { "E", tZONE, -HOUR ( 5) }, + { "F", tZONE, -HOUR ( 6) }, + { "G", tZONE, -HOUR ( 7) }, + { "H", tZONE, -HOUR ( 8) }, + { "I", tZONE, -HOUR ( 9) }, + { "K", tZONE, -HOUR (10) }, + { "L", tZONE, -HOUR (11) }, + { "M", tZONE, -HOUR (12) }, + { "N", tZONE, HOUR ( 1) }, + { "O", tZONE, HOUR ( 2) }, + { "P", tZONE, HOUR ( 3) }, + { "Q", tZONE, HOUR ( 4) }, + { "R", tZONE, HOUR ( 5) }, + { "S", tZONE, HOUR ( 6) }, + { "T", 'T', 0 }, + { "U", tZONE, HOUR ( 8) }, + { "V", tZONE, HOUR ( 9) }, + { "W", tZONE, HOUR (10) }, + { "X", tZONE, HOUR (11) }, + { "Y", tZONE, HOUR (12) }, + { "Z", tZONE, HOUR ( 0) }, + { NULL, 0, 0 } +}; + + + +/* Convert a time zone expressed as HH:MM into an integer count of + minutes. If MM is negative, then S is of the form HHMM and needs + to be picked apart; otherwise, S is of the form HH. As specified in + http://www.opengroup.org/susv3xbd/xbd_chap08.html#tag_08_03, allow + only valid TZ range, and consider first two digits as hours, if no + minutes specified. */ + +static long int +time_zone_hhmm (parser_control *pc, textint s, long int mm) +{ + long int n_minutes; + + /* If the length of S is 1 or 2 and no minutes are specified, + interpret it as a number of hours. */ + if (s.digits <= 2 && mm < 0) + s.value *= 100; + + if (mm < 0) + n_minutes = (s.value / 100) * 60 + s.value % 100; + else + n_minutes = s.value * 60 + (s.negative ? -mm : mm); + + /* If the absolute number of minutes is larger than 24 hours, + arrange to reject it by incrementing pc->zones_seen. Thus, + we allow only values in the range UTC-24:00 to UTC+24:00. */ + if (24 * 60 < labs (n_minutes)) + pc->zones_seen++; + + return n_minutes; +} + +static int +to_hour (long int hours, int meridian) +{ + switch (meridian) + { + default: /* Pacify GCC. */ + case MER24: + return 0 <= hours && hours < 24 ? hours : -1; + case MERam: + return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1; + case MERpm: + return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1; + } +} + +static long int +to_year (textint textyear) +{ + long int year = textyear.value; + + if (year < 0) + year = -year; + + /* XPG4 suggests that years 00-68 map to 2000-2068, and + years 69-99 map to 1969-1999. */ + else if (textyear.digits == 2) + year += year < 69 ? 2000 : 1900; + + return year; +} + +static table const * +lookup_zone (parser_control const *pc, char const *name) +{ + table const *tp; + + for (tp = universal_time_zone_table; tp->name; tp++) + if (strcmp (name, tp->name) == 0) + return tp; + + /* Try local zone abbreviations before those in time_zone_table, as + the local ones are more likely to be right. */ + for (tp = pc->local_time_zone_table; tp->name; tp++) + if (strcmp (name, tp->name) == 0) + return tp; + + for (tp = time_zone_table; tp->name; tp++) + if (strcmp (name, tp->name) == 0) + return tp; + + return NULL; +} + +// #if ! HAVE_TM_GMTOFF +#if 1 // Always true for us +/* Yield the difference between *A and *B, + measured in seconds, ignoring leap seconds. + The body of this function is taken directly from the GNU C Library; + see src/strftime.c. */ +static long int +tm_diff (struct tm const *a, struct tm const *b) +{ + /* Compute intervening leap days correctly even if year is negative. + Take care to avoid int overflow in leap day calculations. */ + int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3); + int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3); + int a100 = a4 / 25 - (a4 % 25 < 0); + int b100 = b4 / 25 - (b4 % 25 < 0); + int a400 = SHR (a100, 2); + int b400 = SHR (b100, 2); + int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); + long int ayear = a->tm_year; + long int years = ayear - b->tm_year; + long int days = (365 * years + intervening_leap_days + + (a->tm_yday - b->tm_yday)); + return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); +} +#endif /* ! HAVE_TM_GMTOFF */ + +static table const * +lookup_word (parser_control const *pc, char *word) +{ + char *p; + char *q; + size_t wordlen; + table const *tp; + bool period_found; + bool abbrev; + + /* Make it uppercase. */ + for (p = word; *p; p++) + { + unsigned char ch = *p; + *p = toupper (ch); + } + + for (tp = meridian_table; tp->name; tp++) + if (strcmp (word, tp->name) == 0) + return tp; + + /* See if we have an abbreviation for a month. */ + wordlen = strlen (word); + abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.'); + + for (tp = month_and_day_table; tp->name; tp++) + if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0) + return tp; + + if ((tp = lookup_zone (pc, word))) + return tp; + + if (strcmp (word, dst_table[0].name) == 0) + return dst_table; + + for (tp = time_units_table; tp->name; tp++) + if (strcmp (word, tp->name) == 0) + return tp; + + /* Strip off any plural and try the units table again. */ + if (word[wordlen - 1] == 'S') + { + word[wordlen - 1] = '\0'; + for (tp = time_units_table; tp->name; tp++) + if (strcmp (word, tp->name) == 0) + return tp; + word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */ + } + + for (tp = relative_time_table; tp->name; tp++) + if (strcmp (word, tp->name) == 0) + return tp; + + /* Military time zones. */ + if (wordlen == 1) + for (tp = military_table; tp->name; tp++) + if (word[0] == tp->name[0]) + return tp; + + /* Drop out any periods and try the time zone table again. */ + for (period_found = false, p = q = word; (*p = *q); q++) + if (*q == '.') + period_found = true; + else + p++; + if (period_found && (tp = lookup_zone (pc, word))) + return tp; + + return NULL; +} + +static int +yylex (union YYSTYPE *lvalp, parser_control *pc) +{ + unsigned char c; + size_t count; + + for (;;) + { + while (c = *pc->input, isspace (c)) + pc->input++; + + if (ISDIGIT (c) || c == '-' || c == '+') + { + char const *p; + int sign; + unsigned long int value; + if (c == '-' || c == '+') + { + sign = c == '-' ? -1 : 1; + while (c = *++pc->input, isspace (c)) + continue; + if (! ISDIGIT (c)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + p = pc->input; + for (value = 0; ; value *= 10) + { + unsigned long int value1 = value + (c - '0'); + if (value1 < value) + return '?'; + value = value1; + c = *++p; + if (! ISDIGIT (c)) + break; + if (ULONG_MAX / 10 < value) + return '?'; + } + if ((c == '.' || c == ',') && ISDIGIT (p[1])) + { + time_t s; + int ns; + int digits; + unsigned long int value1; + + /* Check for overflow when converting value to time_t. */ + if (sign < 0) + { + s = - value; + if (0 < s) + return '?'; + value1 = -s; + } + else + { + s = value; + if (s < 0) + return '?'; + value1 = s; + } + if (value != value1) + return '?'; + + /* Accumulate fraction, to ns precision. */ + p++; + ns = *p++ - '0'; + for (digits = 2; digits <= LOG10_BILLION; digits++) + { + ns *= 10; + if (ISDIGIT (*p)) + ns += *p++ - '0'; + } + + /* Skip excess digits, truncating toward -Infinity. */ + if (sign < 0) + for (; ISDIGIT (*p); p++) + if (*p != '0') + { + ns++; + break; + } + while (ISDIGIT (*p)) + p++; + + /* Adjust to the timespec convention, which is that + tv_nsec is always a positive offset even if tv_sec is + negative. */ + if (sign < 0 && ns) + { + s--; + if (! (s < 0)) + return '?'; + ns = BILLION - ns; + } + + lvalp->timespec.tv_sec = s; + lvalp->timespec.tv_nsec = ns; + pc->input = p; + return sign ? tSDECIMAL_NUMBER : tUDECIMAL_NUMBER; + } + else + { + lvalp->textintval.negative = sign < 0; + if (sign < 0) + { + lvalp->textintval.value = - value; + if (0 < lvalp->textintval.value) + return '?'; + } + else + { + lvalp->textintval.value = value; + if (lvalp->textintval.value < 0) + return '?'; + } + lvalp->textintval.digits = p - pc->input; + pc->input = p; + return sign ? tSNUMBER : tUNUMBER; + } + } + + if (isalpha (c)) + { + char buff[20]; + char *p = buff; + table const *tp; + + do + { + if (p < buff + sizeof buff - 1) + *p++ = c; + c = *++pc->input; + } + while (isalpha (c) || c == '.'); + + *p = '\0'; + tp = lookup_word (pc, buff); + if (! tp) + return '?'; + lvalp->intval = tp->value; + return tp->type; + } + + if (c != '(') + return to_uchar (*pc->input++); + + count = 0; + do + { + c = *pc->input++; + if (c == '\0') + return c; + if (c == '(') + count++; + else if (c == ')') + count--; + } + while (count != 0); + } +} + +/* Do nothing if the parser reports an error. */ +static int +yyerror (parser_control const *pc, + char const *s) +{ + return 0; +} + +/* If *TM0 is the old and *TM1 is the new value of a struct tm after + passing it to mktime, return true if it's OK that mktime returned T. + It's not OK if *TM0 has out-of-range members. */ + +static bool +mktime_ok (struct tm const *tm0, struct tm const *tm1, time_t t) +{ + if (t == (time_t) -1) + { + /* Guard against falsely reporting an error when parsing a time + stamp that happens to equal (time_t) -1, on a host that + supports such a time stamp. */ + tm1 = localtime (&t); + if (!tm1) + return false; + } + + return ! ((tm0->tm_sec ^ tm1->tm_sec) + | (tm0->tm_min ^ tm1->tm_min) + | (tm0->tm_hour ^ tm1->tm_hour) + | (tm0->tm_mday ^ tm1->tm_mday) + | (tm0->tm_mon ^ tm1->tm_mon) + | (tm0->tm_year ^ tm1->tm_year)); +} + +/* A reasonable upper bound for the size of ordinary TZ strings. + Use heap allocation if TZ's length exceeds this. */ +enum { TZBUFSIZE = 100 }; + +/* Return a copy of TZ, stored in TZBUF if it fits, and heap-allocated + otherwise. */ +static char * +get_tz (char tzbuf[TZBUFSIZE]) +{ + char *tz = getenv ("TZ"); + if (tz) + { + size_t tzsize = strlen (tz) + 1; + tz = (tzsize <= TZBUFSIZE + ? memcpy (tzbuf, tz, tzsize) + : xmemdup (tz, tzsize)); + } + return tz; +} + +/* Parse a date/time string, storing the resulting time value into *RESULT. + The string itself is pointed to by P. Return true if successful. + P can be an incomplete or relative time specification; if so, use + *NOW as the basis for the returned time. */ +bool +parse_datetime (struct timespec *result, char const *p, + struct timespec const *now) +{ + time_t Start; + long int Start_ns; + struct tm const *tmp; + struct tm tm = { 0, }; + struct tm tm0 = { 0, }; + parser_control pc; + struct timespec gettime_buffer; + unsigned char c; + bool tz_was_altered = false; + char *tz0 = NULL; + char tz0buf[TZBUFSIZE]; + bool ok = true; + + if (! now) + { + gettime (&gettime_buffer); + now = &gettime_buffer; + } + + Start = now->tv_sec; + Start_ns = now->tv_nsec; + + tmp = localtime (&now->tv_sec); + if (! tmp) + return false; + + while (c = *p, isspace (c)) + p++; + + if (strncmp (p, "TZ=\"", 4) == 0) + { + char const *tzbase = p + 4; + size_t tzsize = 1; + char const *s; + + for (s = tzbase; *s; s++, tzsize++) + if (*s == '\\') + { + s++; + if (! (*s == '\\' || *s == '"')) + break; + } + else if (*s == '"') + { + char *z; + char *tz1; + char tz1buf[TZBUFSIZE]; + bool large_tz = TZBUFSIZE < tzsize; + bool setenv_ok; + tz0 = get_tz (tz0buf); + z = tz1 = large_tz ? g_malloc (tzsize) : tz1buf; + for (s = tzbase; *s != '"'; s++) + *z++ = *(s += *s == '\\'); + *z = '\0'; + setenv_ok = setenv ("TZ", tz1, 1) == 0; + if (large_tz) + free (tz1); + if (!setenv_ok) + goto fail; + tz_was_altered = true; + + p = s + 1; + while (c = *p, isspace (c)) + p++; + + break; + } + } + + /* As documented, be careful to treat the empty string just like + a date string of "0". Without this, an empty string would be + declared invalid when parsed during a DST transition. */ + if (*p == '\0') + p = "0"; + + pc.input = p; + pc.year.value = tmp->tm_year; + pc.year.value += TM_YEAR_BASE; + pc.year.digits = 0; + pc.month = tmp->tm_mon + 1; + pc.day = tmp->tm_mday; + pc.hour = tmp->tm_hour; + pc.minutes = tmp->tm_min; + pc.seconds.tv_sec = tmp->tm_sec; + pc.seconds.tv_nsec = Start_ns; + tm.tm_isdst = tmp->tm_isdst; + + pc.meridian = MER24; + pc.rel = RELATIVE_TIME_0; + pc.timespec_seen = false; + pc.rels_seen = false; + pc.dates_seen = 0; + pc.days_seen = 0; + pc.times_seen = 0; + pc.local_zones_seen = 0; + pc.dsts_seen = 0; + pc.zones_seen = 0; + +#if HAVE_STRUCT_TM_TM_ZONE + pc.local_time_zone_table[0].name = tmp->tm_zone; + pc.local_time_zone_table[0].type = tLOCAL_ZONE; + pc.local_time_zone_table[0].value = tmp->tm_isdst; + pc.local_time_zone_table[1].name = NULL; + + /* Probe the names used in the next three calendar quarters, looking + for a tm_isdst different from the one we already have. */ + { + int quarter; + for (quarter = 1; quarter <= 3; quarter++) + { + time_t probe = Start + quarter * (90 * 24 * 60 * 60); + struct tm const *probe_tm = localtime (&probe); + if (probe_tm && probe_tm->tm_zone + && probe_tm->tm_isdst != pc.local_time_zone_table[0].value) + { + { + pc.local_time_zone_table[1].name = probe_tm->tm_zone; + pc.local_time_zone_table[1].type = tLOCAL_ZONE; + pc.local_time_zone_table[1].value = probe_tm->tm_isdst; + pc.local_time_zone_table[2].name = NULL; + } + break; + } + } + } +#else +#if HAVE_TZNAME + { +# if !HAVE_DECL_TZNAME + extern char *tzname[]; +# endif + int i; + for (i = 0; i < 2; i++) + { + pc.local_time_zone_table[i].name = tzname[i]; + pc.local_time_zone_table[i].type = tLOCAL_ZONE; + pc.local_time_zone_table[i].value = i; + } + pc.local_time_zone_table[i].name = NULL; + } +#else + pc.local_time_zone_table[0].name = NULL; +#endif +#endif + + if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name + && ! strcmp (pc.local_time_zone_table[0].name, + pc.local_time_zone_table[1].name)) + { + /* This locale uses the same abbreviation for standard and + daylight times. So if we see that abbreviation, we don't + know whether it's daylight time. */ + pc.local_time_zone_table[0].value = -1; + pc.local_time_zone_table[1].name = NULL; + } + + if (yyparse (&pc) != 0) + goto fail; + + if (pc.timespec_seen) + *result = pc.seconds; + else + { + if (1 < (pc.times_seen | pc.dates_seen | pc.days_seen | pc.dsts_seen + | (pc.local_zones_seen + pc.zones_seen))) + goto fail; + + tm.tm_year = to_year (pc.year) - TM_YEAR_BASE; + tm.tm_mon = pc.month - 1; + tm.tm_mday = pc.day; + if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen)) + { + tm.tm_hour = to_hour (pc.hour, pc.meridian); + if (tm.tm_hour < 0) + goto fail; + tm.tm_min = pc.minutes; + tm.tm_sec = pc.seconds.tv_sec; + } + else + { + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + pc.seconds.tv_nsec = 0; + } + + /* Let mktime deduce tm_isdst if we have an absolute time stamp. */ + if (pc.dates_seen | pc.days_seen | pc.times_seen) + tm.tm_isdst = -1; + + /* But if the input explicitly specifies local time with or without + DST, give mktime that information. */ + if (pc.local_zones_seen) + tm.tm_isdst = pc.local_isdst; + + tm0 = tm; + + Start = mktime (&tm); + + if (! mktime_ok (&tm0, &tm, Start)) + { + if (! pc.zones_seen) + goto fail; + else + { + /* Guard against falsely reporting errors near the time_t + boundaries when parsing times in other time zones. For + example, suppose the input string "1969-12-31 23:00:00 -0100", + the current time zone is 8 hours ahead of UTC, and the min + time_t value is 1970-01-01 00:00:00 UTC. Then the min + localtime value is 1970-01-01 08:00:00, and mktime will + therefore fail on 1969-12-31 23:00:00. To work around the + problem, set the time zone to 1 hour behind UTC temporarily + by setting TZ="XXX1:00" and try mktime again. */ + + long int time_zone = pc.time_zone; + long int abs_time_zone = time_zone < 0 ? - time_zone : time_zone; + long int abs_time_zone_hour = abs_time_zone / 60; + int abs_time_zone_min = abs_time_zone % 60; + char tz1buf[sizeof "XXX+0:00" + + sizeof pc.time_zone * CHAR_BIT / 3]; + if (!tz_was_altered) + tz0 = get_tz (tz0buf); + sprintf (tz1buf, "XXX%s%ld:%02d", &"-"[time_zone < 0], + abs_time_zone_hour, abs_time_zone_min); + if (setenv ("TZ", tz1buf, 1) != 0) + goto fail; + tz_was_altered = true; + tm = tm0; + Start = mktime (&tm); + if (! mktime_ok (&tm0, &tm, Start)) + goto fail; + } + } + + if (pc.days_seen && ! pc.dates_seen) + { + tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7 + + 7 * (pc.day_ordinal + - (0 < pc.day_ordinal + && tm.tm_wday != pc.day_number))); + tm.tm_isdst = -1; + Start = mktime (&tm); + if (Start == (time_t) -1) + goto fail; + } + + /* Add relative date. */ + if (pc.rel.year | pc.rel.month | pc.rel.day) + { + int year = tm.tm_year + pc.rel.year; + int month = tm.tm_mon + pc.rel.month; + int day = tm.tm_mday + pc.rel.day; + if (((year < tm.tm_year) ^ (pc.rel.year < 0)) + | ((month < tm.tm_mon) ^ (pc.rel.month < 0)) + | ((day < tm.tm_mday) ^ (pc.rel.day < 0))) + goto fail; + tm.tm_year = year; + tm.tm_mon = month; + tm.tm_mday = day; + tm.tm_hour = tm0.tm_hour; + tm.tm_min = tm0.tm_min; + tm.tm_sec = tm0.tm_sec; + tm.tm_isdst = tm0.tm_isdst; + Start = mktime (&tm); + if (Start == (time_t) -1) + goto fail; + } + + /* The only "output" of this if-block is an updated Start value, + so this block must follow others that clobber Start. */ + if (pc.zones_seen) + { + long int delta = pc.time_zone * 60; + time_t t1; +#ifdef HAVE_TM_GMTOFF + delta -= tm.tm_gmtoff; +#else + time_t t = Start; + struct tm const *gmt = gmtime (&t); + if (! gmt) + goto fail; + delta -= tm_diff (&tm, gmt); +#endif + t1 = Start - delta; + if ((Start < t1) != (delta < 0)) + goto fail; /* time_t overflow */ + Start = t1; + } + + /* Add relative hours, minutes, and seconds. On hosts that support + leap seconds, ignore the possibility of leap seconds; e.g., + "+ 10 minutes" adds 600 seconds, even if one of them is a + leap second. Typically this is not what the user wants, but it's + too hard to do it the other way, because the time zone indicator + must be applied before relative times, and if mktime is applied + again the time zone will be lost. */ + { + long int sum_ns = pc.seconds.tv_nsec + pc.rel.ns; + long int normalized_ns = (sum_ns % BILLION + BILLION) % BILLION; + time_t t0 = Start; + long int d1 = 60 * 60 * pc.rel.hour; + time_t t1 = t0 + d1; + long int d2 = 60 * pc.rel.minutes; + time_t t2 = t1 + d2; + intmax_t d3 = pc.rel.seconds; + intmax_t t3 = t2 + d3; + long int d4 = (sum_ns - normalized_ns) / BILLION; + intmax_t t4 = t3 + d4; + time_t t5 = t4; + + if ((d1 / (60 * 60) ^ pc.rel.hour) + | (d2 / 60 ^ pc.rel.minutes) + | ((t1 < t0) ^ (d1 < 0)) + | ((t2 < t1) ^ (d2 < 0)) + | ((t3 < t2) ^ (d3 < 0)) + | ((t4 < t3) ^ (d4 < 0)) + | (t5 != t4)) + goto fail; + + result->tv_sec = t5; + result->tv_nsec = normalized_ns; + } + } + + goto done; + + fail: + ok = false; + done: + if (tz_was_altered) + ok &= (tz0 ? setenv ("TZ", tz0, 1) : unsetenv ("TZ")) == 0; + if (tz0 != tz0buf) + free (tz0); + return ok; +} diff --git a/src/rofiles-fuse/Makefile-inc.am b/src/rofiles-fuse/Makefile-inc.am new file mode 100644 index 0000000..0cc1d9e --- /dev/null +++ b/src/rofiles-fuse/Makefile-inc.am @@ -0,0 +1,27 @@ +# Copyright (C) 2016 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +bin_PROGRAMS += rofiles-fuse + +rofiles_fuse_SOURCES = src/rofiles-fuse/main.c + +rofiles_fuse_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 $(BUILDOPT_FUSE_CFLAGS) \ + $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I $(srcdir)/src/libostree -I $(builddir)/src/libostree \ + -I$(srcdir)/libglnx +rofiles_fuse_LDADD = libglnx.la $(BUILDOPT_FUSE_LIBS) $(OT_INTERNAL_GIO_UNIX_LIBS) libostree-1.la diff --git a/src/rofiles-fuse/main.c b/src/rofiles-fuse/main.c new file mode 100644 index 0000000..4033caa --- /dev/null +++ b/src/rofiles-fuse/main.c @@ -0,0 +1,686 @@ +/* + * Copyright (C) 2015,2016 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#define FUSE_USE_VERSION 26 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "libglnx.h" +#include "ostree.h" + +// Global to store our read-write path +static int basefd = -1; +/* Whether or not to automatically "copyup" (in overlayfs terms). + * What we're really doing is breaking hardlinks. + */ +static gboolean opt_copyup; + +static inline const char * +ENSURE_RELPATH (const char *path) +{ + path = path + strspn (path, "/"); + if (*path == 0) + return "."; + return path; +} + +static int +callback_getattr (const char *path, struct stat *st_data) +{ + path = ENSURE_RELPATH (path); + if (!*path) + { + if (fstat (basefd, st_data) == -1) + return -errno; + } + else + { + if (fstatat (basefd, path, st_data, AT_SYMLINK_NOFOLLOW) == -1) + return -errno; + } + return 0; +} + +static int +callback_readlink (const char *path, char *buf, size_t size) +{ + int r; + + path = ENSURE_RELPATH (path); + + /* Note FUSE wants the string to be always nul-terminated, even if + * truncated. + */ + r = readlinkat (basefd, path, buf, size - 1); + if (r == -1) + return -errno; + buf[r] = '\0'; + return 0; +} + +static int +callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + DIR *dp; + struct dirent *de; + int dfd; + + path = ENSURE_RELPATH (path); + + if (!*path) + { + dfd = fcntl (basefd, F_DUPFD_CLOEXEC, 3); + if (dfd < 0) + return -errno; + lseek (dfd, 0, SEEK_SET); + } + else + { + dfd = openat (basefd, path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); + if (dfd == -1) + return -errno; + } + + /* Transfers ownership of fd */ + dp = fdopendir (dfd); + if (dp == NULL) + return -errno; + + while ((de = readdir (dp)) != NULL) + { + struct stat st; + memset (&st, 0, sizeof (st)); + st.st_ino = de->d_ino; + st.st_mode = de->d_type << 12; + if (filler (buf, de->d_name, &st, 0)) + break; + } + + (void) closedir (dp); + return 0; +} + +static int +callback_mknod (const char *path, mode_t mode, dev_t rdev) +{ + return -EROFS; +} + +static int +callback_mkdir (const char *path, mode_t mode) +{ + path = ENSURE_RELPATH (path); + if (mkdirat (basefd, path, mode) == -1) + return -errno; + return 0; +} + +static int +callback_unlink (const char *path) +{ + path = ENSURE_RELPATH (path); + if (unlinkat (basefd, path, 0) == -1) + return -errno; + return 0; +} + +static int +callback_rmdir (const char *path) +{ + path = ENSURE_RELPATH (path); + if (unlinkat (basefd, path, AT_REMOVEDIR) == -1) + return -errno; + return 0; +} + +static int +callback_symlink (const char *from, const char *to) +{ + struct stat stbuf; + + to = ENSURE_RELPATH (to); + + if (symlinkat (from, basefd, to) == -1) + return -errno; + + if (fstatat (basefd, to, &stbuf, AT_SYMLINK_NOFOLLOW) == -1) + { + fprintf (stderr, "Failed to find newly created symlink '%s': %s\n", + to, g_strerror (errno)); + exit (EXIT_FAILURE); + } + return 0; +} + +static int +callback_rename (const char *from, const char *to) +{ + from = ENSURE_RELPATH (from); + to = ENSURE_RELPATH (to); + if (renameat (basefd, from, basefd, to) == -1) + return -errno; + return 0; +} + +static int +callback_link (const char *from, const char *to) +{ + from = ENSURE_RELPATH (from); + to = ENSURE_RELPATH (to); + if (linkat (basefd, from, basefd, to, 0) == -1) + return -errno; + return 0; +} + +/* Check whether @stbuf refers to a hardlinked regfile or symlink, and if so + * return -EROFS. Otherwise return 0. + */ +static gboolean +can_write_stbuf (const struct stat *stbuf) +{ + /* If it's not a regular file or symlink, ostree won't hardlink it, so allow + * writes - it might be a FIFO or device that somehow + * ended up underneath our mount. + */ + if (!(S_ISREG (stbuf->st_mode) || S_ISLNK (stbuf->st_mode))) + return TRUE; + /* If the object isn't hardlinked, it's OK to write */ + if (stbuf->st_nlink <= 1) + return TRUE; + /* Otherwise, it's a hardlinked file or symlink; it must be + * immutable. + */ + return FALSE; +} + +static int +gioerror_to_errno (GIOErrorEnum e) +{ + /* It's obviously crappy to have to do this but + * we also don't want to try to have "raw errno" versions + * of everything down in ostree_break_hardlink() so... + * let's just reverse map a few ones I think are going to be common. + */ + switch (e) + { + case G_IO_ERROR_NOT_FOUND: + return ENOENT; + case G_IO_ERROR_IS_DIRECTORY: + return EISDIR; + case G_IO_ERROR_PERMISSION_DENIED: + return EPERM; + case G_IO_ERROR_NO_SPACE: + return ENOSPC; + default: + return EIO; + } +} + +static int +verify_write_or_copyup (const char *path, const struct stat *stbuf, + gboolean *out_did_copyup) +{ + struct stat stbuf_local; + + if (out_did_copyup) + *out_did_copyup = FALSE; + + /* If a stbuf wasn't provided, gather it now */ + if (!stbuf) + { + if (fstatat (basefd, path, &stbuf_local, AT_SYMLINK_NOFOLLOW) == -1) + { + if (errno == ENOENT) + return 0; + else + return -errno; + } + stbuf = &stbuf_local; + } + + /* Verify writability, if that fails, perform copy-up if enabled */ + if (!can_write_stbuf (stbuf)) + { + if (opt_copyup) + { + g_autoptr(GError) tmp_error = NULL; + if (!ostree_break_hardlink (basefd, path, FALSE, NULL, &tmp_error)) + return -gioerror_to_errno ((GIOErrorEnum)tmp_error->code); + if (out_did_copyup) + *out_did_copyup = TRUE; + } + else + return -EROFS; + } + + return 0; +} + +/* Given a path (which is absolute), convert it + * to a relative path (even for the caller) and + * perform either write verification or copy-up. + */ +#define PATH_WRITE_ENTRYPOINT(path) do { \ + path = ENSURE_RELPATH (path); \ + int r = verify_write_or_copyup (path, NULL, NULL); \ + if (r != 0) \ + return r; \ + } while (0) + +static int +callback_chmod (const char *path, mode_t mode) +{ + PATH_WRITE_ENTRYPOINT (path); + + /* Note we can't use AT_SYMLINK_NOFOLLOW yet; + * https://marc.info/?l=linux-kernel&m=148830147803162&w=2 + * https://marc.info/?l=linux-fsdevel&m=149193779929561&w=2 + */ + if (fchmodat (basefd, path, mode, 0) != 0) + return -errno; + return 0; +} + +static int +callback_chown (const char *path, uid_t uid, gid_t gid) +{ + PATH_WRITE_ENTRYPOINT (path); + + if (fchownat (basefd, path, uid, gid, AT_SYMLINK_NOFOLLOW) != 0) + return -errno; + return 0; +} + +static int +callback_truncate (const char *path, off_t size) +{ + PATH_WRITE_ENTRYPOINT (path); + + glnx_autofd int fd = openat (basefd, path, O_NOFOLLOW|O_WRONLY); + if (fd == -1) + return -errno; + + if (ftruncate (fd, size) == -1) + return -errno; + + return 0; +} + +static int +callback_utimens (const char *path, const struct timespec tv[2]) +{ + /* This one isn't write-verified, we support changing times + * even for hardlinked files. + */ + path = ENSURE_RELPATH (path); + + if (utimensat (basefd, path, tv, AT_SYMLINK_NOFOLLOW) == -1) + return -errno; + + return 0; +} + +static int +do_open (const char *path, mode_t mode, struct fuse_file_info *finfo) +{ + int fd; + struct stat stbuf; + + path = ENSURE_RELPATH (path); + + if ((finfo->flags & O_ACCMODE) == O_RDONLY) + { + /* Read */ + fd = openat (basefd, path, finfo->flags, mode); + if (fd == -1) + return -errno; + } + else + { + /* Write */ + + /* We need to specially handle O_TRUNC */ + fd = openat (basefd, path, finfo->flags & ~O_TRUNC, mode); + if (fd == -1) + return -errno; + + if (fstat (fd, &stbuf) == -1) + { + (void) close (fd); + return -errno; + } + + gboolean did_copyup; + int r = verify_write_or_copyup (path, &stbuf, &did_copyup); + if (r != 0) + { + (void) close (fd); + return r; + } + + /* In the copyup case, we need to re-open */ + if (did_copyup) + { + (void) close (fd); + /* Note that unlike the initial open, we will pass through + * O_TRUNC. More ideally in this copyup case we'd avoid copying + * the whole file in the first place, but eh. It's not like we're + * high performance anyways. + */ + fd = openat (basefd, path, finfo->flags & ~(O_EXCL|O_CREAT), mode); + if (fd == -1) + return -errno; + } + else + { + /* In the non-copyup case we handle O_TRUNC here, after we've verified + * the hardlink state above with verify_write_or_copyup(). + */ + if (finfo->flags & O_TRUNC) + { + if (ftruncate (fd, 0) == -1) + { + (void) close (fd); + return -errno; + } + } + } + } + + finfo->fh = fd; + + return 0; +} + +static int +callback_open (const char *path, struct fuse_file_info *finfo) +{ + return do_open (path, 0, finfo); +} + +static int +callback_create(const char *path, mode_t mode, struct fuse_file_info *finfo) +{ + return do_open (path, mode, finfo); +} + +static int +callback_read_buf (const char *path, struct fuse_bufvec **bufp, + size_t size, off_t offset, struct fuse_file_info *finfo) +{ + struct fuse_bufvec *src; + + src = malloc (sizeof (struct fuse_bufvec)); + if (src == NULL) + return -ENOMEM; + + *src = FUSE_BUFVEC_INIT (size); + + src->buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; + src->buf[0].fd = finfo->fh; + src->buf[0].pos = offset; + *bufp = src; + + return 0; +} + +static int +callback_read (const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *finfo) +{ + int r; + r = pread (finfo->fh, buf, size, offset); + if (r == -1) + return -errno; + return r; +} + +static int +callback_write_buf (const char *path, struct fuse_bufvec *buf, off_t offset, + struct fuse_file_info *finfo) +{ + struct fuse_bufvec dst = FUSE_BUFVEC_INIT (fuse_buf_size (buf)); + + dst.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; + dst.buf[0].fd = finfo->fh; + dst.buf[0].pos = offset; + + return fuse_buf_copy (&dst, buf, FUSE_BUF_SPLICE_NONBLOCK); +} + +static int +callback_write (const char *path, const char *buf, size_t size, off_t offset, + struct fuse_file_info *finfo) +{ + int r; + r = pwrite (finfo->fh, buf, size, offset); + if (r == -1) + return -errno; + return r; +} + +static int +callback_statfs (const char *path, struct statvfs *st_buf) +{ + if (fstatvfs (basefd, st_buf) == -1) + return -errno; + return 0; +} + +static int +callback_release (const char *path, struct fuse_file_info *finfo) +{ + (void) close (finfo->fh); + return 0; +} + +static int +callback_fsync (const char *path, int crap, struct fuse_file_info *finfo) +{ + if (fsync (finfo->fh) == -1) + return -errno; + return 0; +} + +static int +callback_access (const char *path, int mode) +{ + path = ENSURE_RELPATH (path); + + /* Apparently at least GNU coreutils rm calls `faccessat(W_OK)` + * before trying to do an unlink. So...we'll just lie about + * writable access here. + */ + if (faccessat (basefd, path, mode, AT_SYMLINK_NOFOLLOW) == -1) + return -errno; + return 0; +} + +static int +callback_setxattr (const char *path, const char *name, const char *value, + size_t size, int flags) +{ + return -ENOTSUP; +} + +static int +callback_getxattr (const char *path, const char *name, char *value, + size_t size) +{ + return -ENOTSUP; +} + +/* + * List the supported extended attributes. + */ +static int +callback_listxattr (const char *path, char *list, size_t size) +{ + return -ENOTSUP; + +} + +/* + * Remove an extended attribute. + */ +static int +callback_removexattr (const char *path, const char *name) +{ + return -ENOTSUP; + +} + +struct fuse_operations callback_oper = { + .getattr = callback_getattr, + .readlink = callback_readlink, + .readdir = callback_readdir, + .mknod = callback_mknod, + .mkdir = callback_mkdir, + .symlink = callback_symlink, + .unlink = callback_unlink, + .rmdir = callback_rmdir, + .rename = callback_rename, + .link = callback_link, + .chmod = callback_chmod, + .chown = callback_chown, + .truncate = callback_truncate, + .utimens = callback_utimens, + .create = callback_create, + .open = callback_open, + .read_buf = callback_read_buf, + .read = callback_read, + .write_buf = callback_write_buf, + .write = callback_write, + .statfs = callback_statfs, + .release = callback_release, + .fsync = callback_fsync, + .access = callback_access, + + /* Extended attributes support for userland interaction */ + .setxattr = callback_setxattr, + .getxattr = callback_getxattr, + .listxattr = callback_listxattr, + .removexattr = callback_removexattr +}; + +enum { + KEY_HELP, + KEY_VERSION, + KEY_COPYUP, +}; + +static void +usage (const char *progname) +{ + fprintf (stdout, + "usage: %s basepath mountpoint [options]\n" + "\n" + " Makes basepath visible at mountpoint such that files are read-only, directories are writable\n" + "\n" + "general options:\n" + " -o opt,[opt...] mount options\n" + " -h --help print help\n" + "\n", progname); +} + +static int +rofs_parse_opt (void *data, const char *arg, int key, + struct fuse_args *outargs) +{ + (void) data; + + switch (key) + { + case FUSE_OPT_KEY_NONOPT: + if (basefd == -1) + { + basefd = openat (AT_FDCWD, arg, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); + if (basefd == -1) + err (1, "opening rootfs %s", arg); + return 0; + } + else + { + return 1; + } + case FUSE_OPT_KEY_OPT: + return 1; + case KEY_HELP: + usage (outargs->argv[0]); + exit (EXIT_SUCCESS); + case KEY_COPYUP: + opt_copyup = TRUE; + return 0; + default: + fprintf (stderr, "see `%s -h' for usage\n", outargs->argv[0]); + exit (EXIT_FAILURE); + } + return 1; +} + +static struct fuse_opt rofs_opts[] = { + FUSE_OPT_KEY ("-h", KEY_HELP), + FUSE_OPT_KEY ("--help", KEY_HELP), + FUSE_OPT_KEY ("-V", KEY_VERSION), + FUSE_OPT_KEY ("--version", KEY_VERSION), + FUSE_OPT_KEY ("--copyup", KEY_COPYUP), + FUSE_OPT_END +}; + +int +main (int argc, char *argv[]) +{ + struct fuse_args args = FUSE_ARGS_INIT (argc, argv); + int res; + + res = fuse_opt_parse (&args, &basefd, rofs_opts, rofs_parse_opt); + if (res != 0) + { + fprintf (stderr, "Invalid arguments\n"); + fprintf (stderr, "see `%s -h' for usage\n", argv[0]); + exit (EXIT_FAILURE); + } + if (basefd == -1) + { + fprintf (stderr, "Missing basepath\n"); + fprintf (stderr, "see `%s -h' for usage\n", argv[0]); + exit (EXIT_FAILURE); + } + + fuse_main (args.argc, args.argv, &callback_oper, NULL); + + return 0; +} diff --git a/src/switchroot/ostree-mount-util.h b/src/switchroot/ostree-mount-util.h new file mode 100644 index 0000000..fb2d02b --- /dev/null +++ b/src/switchroot/ostree-mount-util.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2011,2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef __OSTREE_MOUNT_UTIL_H_ +#define __OSTREE_MOUNT_UTIL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define INITRAMFS_MOUNT_VAR "/run/ostree/initramfs-mount-var" +#define _OSTREE_SYSROOT_READONLY_STAMP "/run/ostree-sysroot-ro.stamp" + +static inline int +path_is_on_readonly_fs (const char *path) +{ + struct statvfs stvfsbuf; + + if (statvfs (path, &stvfsbuf) == -1) + err (EXIT_FAILURE, "statvfs(%s)", path); + + return (stvfsbuf.f_flag & ST_RDONLY) != 0; +} + +static inline char * +read_proc_cmdline (void) +{ + FILE *f = fopen("/proc/cmdline", "r"); + char *cmdline = NULL; + size_t len; + + if (!f) + goto out; + + /* Note that /proc/cmdline will not end in a newline, so getline + * will fail unelss we provide a length. + */ + if (getline (&cmdline, &len, f) < 0) + goto out; + /* ... but the length will be the size of the malloc buffer, not + * strlen(). Fix that. + */ + len = strlen (cmdline); + + if (cmdline[len-1] == '\n') + cmdline[len-1] = '\0'; +out: + if (f) + fclose (f); + return cmdline; +} + +static inline char * +read_proc_cmdline_ostree (void) +{ + char *cmdline = NULL; + const char *iter; + char *ret = NULL; + + cmdline = read_proc_cmdline (); + if (!cmdline) + err (EXIT_FAILURE, "failed to read /proc/cmdline"); + + iter = cmdline; + while (iter != NULL) + { + const char *next = strchr (iter, ' '); + const char *next_nonspc = next; + while (next_nonspc && *next_nonspc == ' ') + next_nonspc += 1; + if (strncmp (iter, "ostree=", strlen ("ostree=")) == 0) + { + const char *start = iter + strlen ("ostree="); + if (next) + ret = strndup (start, next - start); + else + ret = strdup (start); + break; + } + iter = next_nonspc; + } + + free (cmdline); + return ret; +} + +/* This is an API for other projects to determine whether or not the + * currently running system is ostree-controlled. + */ +static inline void +touch_run_ostree (void) +{ + int fd = open ("/run/ostree-booted", O_CREAT | O_WRONLY | O_NOCTTY | O_CLOEXEC, 0640); + /* We ignore failures here in case /run isn't mounted...not much we + * can do about that, but we don't want to fail. + */ + if (fd == -1) + return; + (void) close (fd); +} + +#endif /* __OSTREE_MOUNT_UTIL_H_ */ diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c new file mode 100644 index 0000000..8a68e1f --- /dev/null +++ b/src/switchroot/ostree-prepare-root.c @@ -0,0 +1,392 @@ +/* -*- c-file-style: "gnu" -*- + * Switch to new root directory and start init. + * + * Copyright 2011,2012,2013 Colin Walters + * + * Based on code from util-linux/sys-utils/switch_root.c, + * Copyright 2002-2009 Red Hat, Inc. All rights reserved. + * Authors: + * Peter Jones + * Jeremy Katz + * + * Relicensed with permission to LGPLv2+. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* The high level goal of ostree-prepare-root.service is to run inside + * the initial ram disk (if one is in use) and set up the `/` mountpoint + * to be the deployment root, using the ostree= kernel commandline + * argument to find the target deployment root. + * + * It's really the heart of how ostree works - basically multiple + * hardlinked chroot() targets are maintained, this one does the equivalent + * of chroot(). + * + * If using systemd, an excellent reference is `man bootup`. This + * service runs Before=initrd-root-fs.target. At this point it's + * assumed that the block storage and root filesystem are mounted at + * /sysroot - i.e. /sysroot points to the *physical* root before + * this service runs. After, `/` is the deployment root. + * + * There is also a secondary mode for this service when an initrd isn't + * used - instead the binary must be statically linked (and the kernel + * must have mounted the rootfs itself) - then we set things up and + * exec the real init directly. This can be popular in embedded + * systems to increase bootup speed. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_LIBSYSTEMD) && !defined(OSTREE_PREPARE_ROOT_STATIC) +#define USE_LIBSYSTEMD +#endif + +#ifdef USE_LIBSYSTEMD +#include +#define OSTREE_PREPARE_ROOT_DEPLOYMENT_MSG SD_ID128_MAKE(71,70,33,6a,73,ba,46,01,ba,d3,1a,f8,88,aa,0d,f7) +#endif + +#include "ostree-mount-util.h" + +/* Initialized early in main */ +static bool running_as_pid1; + +static inline bool +sysroot_is_configured_ro (const char *sysroot) +{ + char * config_path = NULL; + assert (asprintf (&config_path, "%s/ostree/repo/config", sysroot) != -1); + FILE *f = fopen(config_path, "r"); + if (!f) + { + fprintf (stderr, "Missing expected repo config: %s\n", config_path); + free (config_path); + return false; + } + free (config_path); + + bool ret = false; + char *line = NULL; + size_t len = 0; + ssize_t nread; + /* Note getline() will reuse the previous buffer */ + bool in_sysroot = false; + while ((nread = getline (&line, &len, f)) != -1) + { + /* This is an awful hack to avoid depending on GLib in the + * initramfs right now. + */ + if (strstr (line, "[sysroot]") == line) + in_sysroot = true; + else if (*line == '[') + in_sysroot = false; + else if (in_sysroot && strstr (line, "readonly=true") == line) + { + ret = true; + break; + } + } + + fclose (f); + free (line); + return ret; +} + +static char* +resolve_deploy_path (const char * root_mountpoint) +{ + char destpath[PATH_MAX]; + struct stat stbuf; + char *ostree_target, *deploy_path; + + ostree_target = read_proc_cmdline_ostree (); + if (!ostree_target) + errx (EXIT_FAILURE, "No OSTree target; expected ostree=/ostree/boot.N/..."); + + snprintf (destpath, sizeof(destpath), "%s/%s", root_mountpoint, ostree_target); + if (lstat (destpath, &stbuf) < 0) + err (EXIT_FAILURE, "Couldn't find specified OSTree root '%s'", destpath); + if (!S_ISLNK (stbuf.st_mode)) + errx (EXIT_FAILURE, "OSTree target is not a symbolic link: %s", destpath); + deploy_path = realpath (destpath, NULL); + if (deploy_path == NULL) + err (EXIT_FAILURE, "realpath(%s) failed", destpath); + if (stat (deploy_path, &stbuf) < 0) + err (EXIT_FAILURE, "stat(%s) failed", deploy_path); + /* Quiet logs if there's no journal */ +#ifdef USE_LIBSYSTEMD + const char *resolved_path = deploy_path + strlen (root_mountpoint); + sd_journal_send ("MESSAGE=Resolved OSTree target to: %s", deploy_path, + "MESSAGE_ID=" SD_ID128_FORMAT_STR, + SD_ID128_FORMAT_VAL(OSTREE_PREPARE_ROOT_DEPLOYMENT_MSG), + "DEPLOYMENT_PATH=%s", resolved_path, + "DEPLOYMENT_DEVICE=%u", stbuf.st_dev, + "DEPLOYMENT_INODE=%u", stbuf.st_ino, + NULL); +#endif + return deploy_path; +} + +static int +pivot_root(const char * new_root, const char * put_old) +{ + return syscall(__NR_pivot_root, new_root, put_old); +} + +int +main(int argc, char *argv[]) +{ + /* If we're pid 1, that means there's no initramfs; in this situation + * various defaults change: + * + * - Assume that the target root is / + * - Quiet logging as there's no journal + * etc. + */ + running_as_pid1 = (getpid () == 1); + + const char *root_arg = NULL; + bool we_mounted_proc = false; + if (running_as_pid1) + { + root_arg = "/"; + } + else + { + if (argc < 2) + err (EXIT_FAILURE, "usage: ostree-prepare-root SYSROOT"); + root_arg = argv[1]; + } + + struct stat stbuf; + if (stat ("/proc/cmdline", &stbuf) < 0) + { + if (errno != ENOENT) + err (EXIT_FAILURE, "stat(\"/proc/cmdline\") failed"); + /* We need /proc mounted for /proc/cmdline and realpath (on musl) to + * work: */ + if (mount ("proc", "/proc", "proc", 0, NULL) < 0) + err (EXIT_FAILURE, "failed to mount proc on /proc"); + we_mounted_proc = 1; + } + + const char *root_mountpoint = realpath (root_arg, NULL); + if (root_mountpoint == NULL) + err (EXIT_FAILURE, "realpath(\"%s\")", root_arg); + char *deploy_path = resolve_deploy_path (root_mountpoint); + + if (we_mounted_proc) + { + /* Leave the filesystem in the state that we found it: */ + if (umount ("/proc")) + err (EXIT_FAILURE, "failed to umount proc from /proc"); + } + + /* Work-around for a kernel bug: for some reason the kernel + * refuses switching root if any file systems are mounted + * MS_SHARED. Hence remount them MS_PRIVATE here as a + * work-around. + * + * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */ + if (mount (NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0) + err (EXIT_FAILURE, "failed to make \"/\" private mount"); + + /* Make deploy_path a bind mount, so we can move it later */ + if (mount (deploy_path, deploy_path, NULL, MS_BIND, NULL) < 0) + err (EXIT_FAILURE, "failed to make initial bind mount %s", deploy_path); + + /* chdir to our new root. We need to do this after bind-mounting it over + * itself otherwise our cwd is still on the non-bind-mounted filesystem + * below. */ + if (chdir (deploy_path) < 0) + err (EXIT_FAILURE, "failed to chdir to deploy_path"); + + /* Query the repository configuration - this is an operating system builder + * choice. More info: https://github.com/ostreedev/ostree/pull/1767 + */ + const bool sysroot_readonly = sysroot_is_configured_ro (root_arg); + const bool sysroot_currently_writable = !path_is_on_readonly_fs (root_arg); + +#ifdef USE_LIBSYSTEMD + sd_journal_send ("MESSAGE=sysroot configured read-only: %d, currently writable: %d", + (int)sysroot_readonly, (int)sysroot_currently_writable, NULL); +#endif + if (sysroot_readonly) + { + if (!sysroot_currently_writable) + errx (EXIT_FAILURE, "sysroot=readonly currently requires writable / in initramfs"); + /* Now, /etc is not normally a bind mount, but if we have a readonly + * sysroot, we still need a writable /etc. And to avoid race conditions + * we ensure it's writable in the initramfs, before we switchroot at all. + */ + if (mount ("/etc", "/etc", NULL, MS_BIND, NULL) < 0) + err (EXIT_FAILURE, "failed to make /etc a bind mount"); + /* Pass on the fact that we discovered a readonly sysroot to ostree-remount.service */ + int fd = open (_OSTREE_SYSROOT_READONLY_STAMP, O_WRONLY | O_CREAT | O_CLOEXEC, 0644); + if (fd < 0) + err (EXIT_FAILURE, "failed to create %s", _OSTREE_SYSROOT_READONLY_STAMP); + (void) close (fd); + } + + /* Default to true, but in the systemd case, default to false because it's handled by + * ostree-system-generator. */ + bool mount_var = true; +#ifdef HAVE_SYSTEMD_AND_LIBMOUNT + mount_var = false; +#endif + + /* file in /run can override the default behaviour so that we definitely mount /var */ + if (lstat (INITRAMFS_MOUNT_VAR, &stbuf) == 0) + mount_var = true; + + /* Link to the deployment's /var */ + if (mount_var && mount ("../../var", "var", NULL, MS_BIND, NULL) < 0) + err (EXIT_FAILURE, "failed to bind mount ../../var to var"); + + char srcpath[PATH_MAX]; + /* If /boot is on the same partition, use a bind mount to make it visible + * at /boot inside the deployment. */ + snprintf (srcpath, sizeof(srcpath), "%s/boot/loader", root_mountpoint); + if (lstat (srcpath, &stbuf) == 0 && S_ISLNK (stbuf.st_mode)) + { + if (lstat ("boot", &stbuf) == 0 && S_ISDIR (stbuf.st_mode)) + { + snprintf (srcpath, sizeof(srcpath), "%s/boot", root_mountpoint); + if (mount (srcpath, "boot", NULL, MS_BIND, NULL) < 0) + err (EXIT_FAILURE, "failed to bind mount %s to boot", srcpath); + } + } + + /* Do we have a persistent overlayfs for /usr? If so, mount it now. */ + if (lstat (".usr-ovl-work", &stbuf) == 0) + { + const char usr_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work"; + + /* Except overlayfs barfs if we try to mount it on a read-only + * filesystem. For this use case I think admins are going to be + * okay if we remount the rootfs here, rather than waiting until + * later boot and `systemd-remount-fs.service`. + */ + if (path_is_on_readonly_fs (".")) + { + if (mount (".", ".", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) + err (EXIT_FAILURE, "failed to remount rootfs writable (for overlayfs)"); + } + + if (mount ("overlay", "usr", "overlay", 0, usr_ovl_options) < 0) + err (EXIT_FAILURE, "failed to mount /usr overlayfs"); + } + else + { + /* Otherwise, a read-only bind mount for /usr */ + if (mount ("usr", "usr", NULL, MS_BIND, NULL) < 0) + err (EXIT_FAILURE, "failed to bind mount (class:readonly) /usr"); + if (mount ("usr", "usr", NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) < 0) + err (EXIT_FAILURE, "failed to bind mount (class:readonly) /usr"); + } + + + /* We only stamp /run now if we're running in an initramfs, i.e. we're + * not pid 1. Otherwise it's handled later via ostree-system-generator. + * https://mail.gnome.org/archives/ostree-list/2018-March/msg00012.html + * https://github.com/ostreedev/ostree/pull/1675 + */ + if (!running_as_pid1) + touch_run_ostree (); + + if (strcmp(root_mountpoint, "/") == 0) + { + /* pivot_root rotates two mount points around. In this instance . (the + * deploy location) becomes / and the existing / becomes /sysroot. We + * have to use pivot_root rather than mount --move in this instance + * because our deploy location is mounted as a subdirectory of the real + * sysroot, so moving sysroot would also move the deploy location. In + * reality attempting mount --move would fail with EBUSY. */ + if (pivot_root (".", "sysroot") < 0) + err (EXIT_FAILURE, "failed to pivot_root to deployment"); + } + else + { + /* In this instance typically we have our ready made-up up root at + * /sysroot/ostree/deploy/.../ (deploy_path) and the real rootfs at + * /sysroot (root_mountpoint). We want to end up with our made-up root at + * /sysroot/ and the real rootfs under /sysroot/sysroot as systemd will be + * responsible for moving /sysroot to /. + * + * We need to do this in 3 moves to avoid trying to move /sysroot under + * itself: + * + * 1. /sysroot/ostree/deploy/... -> /sysroot.tmp + * 2. /sysroot -> /sysroot.tmp/sysroot + * 3. /sysroot.tmp -> /sysroot + */ + if (mkdir ("/sysroot.tmp", 0755) < 0) + err (EXIT_FAILURE, "couldn't create temporary sysroot /sysroot.tmp"); + + if (mount (deploy_path, "/sysroot.tmp", NULL, MS_MOVE, NULL) < 0) + err (EXIT_FAILURE, "failed to MS_MOVE '%s' to '/sysroot.tmp'", deploy_path); + + if (mount (root_mountpoint, "sysroot", NULL, MS_MOVE, NULL) < 0) + err (EXIT_FAILURE, "failed to MS_MOVE '%s' to 'sysroot'", root_mountpoint); + + if (mount (".", root_mountpoint, NULL, MS_MOVE, NULL) < 0) + err (EXIT_FAILURE, "failed to MS_MOVE %s to %s", deploy_path, root_mountpoint); + + if (rmdir ("/sysroot.tmp") < 0) + err (EXIT_FAILURE, "couldn't remove temporary sysroot /sysroot.tmp"); + } + + /* The /sysroot mount needs to be private to avoid having a mount for e.g. /var/cache + * also propagate to /sysroot/ostree/deploy/$stateroot/var/cache + * + * Now in reality, today this is overridden by systemd: the *actual* way we fix this up + * is in ostree-remount.c. But let's do it here to express the semantics we want + * at the very start (perhaps down the line systemd will have compile/runtime option + * to say that the initramfs environment did everything right from the start). + */ + if (mount ("none", "sysroot", NULL, MS_PRIVATE, NULL) < 0) + err (EXIT_FAILURE, "remounting 'sysroot' private"); + + if (running_as_pid1) + { + execl ("/sbin/init", "/sbin/init", NULL); + err (EXIT_FAILURE, "failed to exec init inside ostree"); + } + else + { + exit (EXIT_SUCCESS); + } +} diff --git a/src/switchroot/ostree-remount.c b/src/switchroot/ostree-remount.c new file mode 100644 index 0000000..5c313c8 --- /dev/null +++ b/src/switchroot/ostree-remount.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2011 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ostree-mount-util.h" +#include "glnx-backport-autocleanups.h" + +static void +do_remount (const char *target, + bool writable) +{ + struct stat stbuf; + if (lstat (target, &stbuf) < 0) + return; + /* Silently ignore symbolic links; we expect these to point to + * /sysroot, and thus there isn't a bind mount there. + */ + if (S_ISLNK (stbuf.st_mode)) + return; + /* If not a mountpoint, skip it */ + struct statvfs stvfsbuf; + if (statvfs (target, &stvfsbuf) == -1) + return; + + const bool currently_writable = ((stvfsbuf.f_flag & ST_RDONLY) == 0); + if (writable == currently_writable) + return; + + int mnt_flags = MS_REMOUNT | MS_SILENT; + if (!writable) + mnt_flags |= MS_RDONLY; + if (mount (target, target, NULL, mnt_flags, NULL) < 0) + { + /* Also ignore EINVAL - if the target isn't a mountpoint + * already, then assume things are OK. + */ + if (errno != EINVAL) + err (EXIT_FAILURE, "failed to remount(%s) %s", writable ? "rw" : "ro", target); + else + return; + } + + printf ("Remounted %s: %s\n", writable ? "rw" : "ro", target); +} + +int +main(int argc, char *argv[]) +{ + /* When systemd is in use this is normally created via the generator, but + * we ensure it's created here as well for redundancy. + */ + touch_run_ostree (); + + /* The /sysroot mount needs to be private to avoid having a mount for e.g. /var/cache + * also propagate to /sysroot/ostree/deploy/$stateroot/var/cache + * + * Today systemd remounts / (recursively) as shared, so we're undoing that as early + * as possible. See also a copy of this in ostree-prepare-root.c. + */ + if (mount ("none", "/sysroot", NULL, MS_REC | MS_PRIVATE, NULL) < 0) + perror ("warning: While remounting /sysroot MS_PRIVATE"); + + if (path_is_on_readonly_fs ("/")) + { + /* If / isn't writable, don't do any remounts; we don't want + * to clear the readonly flag in that case. + */ + exit (EXIT_SUCCESS); + } + + /* Handle remounting /sysroot read-only now */ + if (unlink (_OSTREE_SYSROOT_READONLY_STAMP) == 0) + { + do_remount ("/sysroot", false); + } + + /* If /var was created as as an OSTree default bind mount (instead of being a separate filesystem) + * then remounting the root mount read-only also remounted it. + * So just like /etc, we need to make it read-write by default. + * If it was a separate filesystem, we expect it to be writable anyways, + * so it doesn't hurt to remount it if so. + * + * And if we started out with a writable system root, then we need + * to ensure that the /var bind mount created by the systemd generator + * is writable too. + */ + do_remount ("/var", true); + + exit (EXIT_SUCCESS); +} diff --git a/src/switchroot/ostree-system-generator.c b/src/switchroot/ostree-system-generator.c new file mode 100644 index 0000000..78bca7c --- /dev/null +++ b/src/switchroot/ostree-system-generator.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2017 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include + +#include "ostree-cmdprivate.h" +#include "ostree-mount-util.h" + +static const char *arg_dest = "/tmp"; +static const char *arg_dest_late = "/tmp"; + +/* This program is a simple stub that calls the implementation that + * lives inside libostree. + */ +int +main(int argc, char *argv[]) +{ + /* We conflict with the magic ostree-mount-deployment-var file for ostree-prepare-root */ + { struct stat stbuf; + if (fstatat (AT_FDCWD, INITRAMFS_MOUNT_VAR, &stbuf, 0) == 0) + { + if (unlinkat (AT_FDCWD, INITRAMFS_MOUNT_VAR, 0) < 0) + err (EXIT_FAILURE, "Can't unlink " INITRAMFS_MOUNT_VAR); + exit (EXIT_SUCCESS); + } + } + + if (argc > 1 && argc != 4) + errx (EXIT_FAILURE, "This program takes three or no arguments"); + + if (argc > 1) + arg_dest = argv[1]; + if (argc > 3) + arg_dest_late = argv[3]; + + /* If we're installed on a system which isn't using OSTree for boot (e.g. + * package installed as a dependency for flatpak or whatever), silently + * exit so that we don't error, but at the same time work where switchroot + * is PID 1 (and so hasn't created /run/ostree-booted). + */ + char *ostree_cmdline = read_proc_cmdline_ostree (); + if (!ostree_cmdline) + exit (EXIT_SUCCESS); + + /* See comments in ostree-prepare-root.c for this. + * + * It's a lot easier for various bits of userspace to check for + * a file versus parsing the kernel cmdline. So let's ensure + * the stamp file is created here too. + */ + touch_run_ostree (); + + { g_autoptr(GError) local_error = NULL; + if (!ostree_cmd__private__()->ostree_system_generator (ostree_cmdline, arg_dest, NULL, arg_dest_late, &local_error)) + errx (EXIT_FAILURE, "%s", local_error->message); + } + + exit (EXIT_SUCCESS); +} diff --git a/tests/admin-test.sh b/tests/admin-test.sh new file mode 100644 index 0000000..3aab74c --- /dev/null +++ b/tests/admin-test.sh @@ -0,0 +1,383 @@ +# This file is to be sourced, not executed + +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +echo "1..$((28 + ${extra_admin_tests:-0}))" + +mkdir sysrootmin +${CMD_PREFIX} ostree admin init-fs --modern sysrootmin +assert_has_dir sysrootmin/boot +assert_has_dir sysrootmin/ostree/repo +assert_not_has_dir sysrootmin/home +rm sysrootmin -rf +echo "ok init-fs --modern" + +function validate_bootloader() { + cd ${test_tmpdir}; + bootloader="" + if test -f sysroot/boot/syslinux/syslinux.cfg; then + bootloader="syslinux" + elif test -f sysroot/boot/grub2/grub.cfg; then + bootloader="grub2" + fi + if test -n "${bootloader}"; then + $(dirname $0)/bootloader-entries-crosscheck.py sysroot ${bootloader} + fi + cd - +} + +# Test generate_deployment_refs() +assert_ostree_deployment_refs() { + ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo refs ostree | sort > ostree-refs.txt + (for v in "$@"; do echo $v; done) | sort > ostree-refs-expected.txt + diff -u ostree-refs{-expected,}.txt +} + +orig_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +export rev +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +new_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) +assert_not_streq "${orig_mtime}" "${new_mtime}" +${CMD_PREFIX} ostree admin status | tee status.txt +assert_not_file_has_content status.txt "pending" +assert_not_file_has_content status.txt "rollback" +validate_bootloader + +echo "ok deploy command" + +${CMD_PREFIX} ostree admin --print-current-dir > curdir +assert_file_has_content curdir ^`pwd`/sysroot/ostree/deploy/testos/deploy/${rev}\.0$ + +echo "ok --print-current-dir" + +# Test layout of bootloader config and refs +assert_not_has_dir sysroot/boot/loader.0 +assert_has_dir sysroot/boot/loader.1 +assert_has_dir sysroot/ostree/boot.1.1 +assert_has_file sysroot/boot/loader/entries/ostree-1-testos.conf +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.* root=LABEL=MOO' +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.* quiet' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' +assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' +assert_ostree_deployment_refs 1/1/0 +${CMD_PREFIX} ostree admin status +echo "ok layout" + +if ${CMD_PREFIX} ostree admin deploy --stage --os=testos testos:testos/buildmaster/x86_64-runtime 2>err.txt; then + fatal "staged when not booted" +fi +assert_file_has_content_literal err.txt "Cannot stage a deployment when not currently booted into an OSTree system" +echo "ok staging does not work when not booted" + +orig_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime +new_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) +assert_not_streq "${orig_mtime}" "${new_mtime}" +# Need a new bootversion, sine we now have two deployments +assert_has_dir sysroot/boot/loader.0 +assert_not_has_dir sysroot/boot/loader.1 +assert_has_dir sysroot/ostree/boot.0.1 +assert_not_has_dir sysroot/ostree/boot.0.0 +assert_not_has_dir sysroot/ostree/boot.1.0 +assert_not_has_dir sysroot/ostree/boot.1.1 +# Ensure we propagated kernel arguments from previous deployment +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.* root=LABEL=MOO' +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.1/etc/os-release 'NAME=TestOS' +assert_file_has_content sysroot/ostree/boot.0/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' +assert_ostree_deployment_refs 0/1/{0,1} +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok second deploy" + +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime +# Keep the same bootversion +assert_has_dir sysroot/boot/loader.0 +assert_not_has_dir sysroot/boot/loader.1 +# But swap subbootversion +assert_has_dir sysroot/ostree/boot.0.0 +assert_not_has_dir sysroot/ostree/boot.0.1 +assert_ostree_deployment_refs 0/0/{0,1} +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok third deploy (swap)" + +${CMD_PREFIX} ostree admin os-init otheros + +${CMD_PREFIX} ostree admin deploy --os=otheros testos/buildmaster/x86_64-runtime +assert_not_has_dir sysroot/boot/loader.0 +assert_has_dir sysroot/boot/loader.1 +assert_has_file sysroot/boot/loader/entries/ostree-2-testos.conf +assert_has_file sysroot/boot/loader/entries/ostree-3-otheros.conf +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.1/etc/os-release 'NAME=TestOS' +assert_file_has_content sysroot/ostree/deploy/otheros/deploy/${rev}.0/etc/os-release 'NAME=TestOS' +assert_ostree_deployment_refs 1/1/{0,1,2} +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok independent deploy" + +${CMD_PREFIX} ostree admin deploy --retain --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/loader.0 +assert_not_has_dir sysroot/boot/loader.1 +assert_has_file sysroot/boot/loader/entries/ostree-4-testos.conf +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.2/etc/os-release 'NAME=TestOS' +assert_has_file sysroot/boot/loader/entries/ostree-2-testos.conf +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/os-release 'NAME=TestOS' +${CMD_PREFIX} ostree admin status +assert_ostree_deployment_refs 0/1/{0,1,2,3} +validate_bootloader + +echo "ok fourth deploy (retain)" + +echo "a new local config file" > sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/a-new-config-file +rm -r sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/testdirectory +rm sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/aconfigfile +ln -s /ENOENT sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/a-new-broken-symlink +${CMD_PREFIX} ostree admin deploy --retain --os=testos testos:testos/buildmaster/x86_64-runtime +assert_not_has_dir sysroot/boot/loader.0 +assert_has_dir sysroot/boot/loader.1 +link=sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/a-new-broken-symlink +if ! test -L ${link}; then + ls -al ${link} + fatal "Not a symlink: ${link}" +fi +linktarget=$(readlink ${link}) +assert_streq "${linktarget}" /ENOENT +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/os-release 'NAME=TestOS' +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/os-release 'NAME=TestOS' +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/a-new-config-file 'a new local config file' +assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/aconfigfile +${CMD_PREFIX} ostree admin status +validate_bootloader +echo "ok deploy with modified /etc" + +# we now have 5 deployments, let's bring that back down to 1 +for i in $(seq 4); do + ${CMD_PREFIX} ostree admin undeploy 0 +done +assert_has_file sysroot/boot/loader/entries/ostree-1-testos.conf +assert_not_has_file sysroot/boot/loader/entries/ostree-2-testos.conf +assert_not_has_file sysroot/boot/loader/entries/ostree-3-otheros.conf +${CMD_PREFIX} ostree admin deploy --not-as-default --os=otheros testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/loader.0 +assert_not_has_dir sysroot/boot/loader.1 +assert_has_file sysroot/boot/loader/entries/ostree-2-testos.conf +assert_has_file sysroot/boot/loader/entries/ostree-1-otheros.conf +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok deploy --not-as-default" + +${CMD_PREFIX} ostree admin deploy --retain-rollback --os=otheros testos:testos/buildmaster/x86_64-runtime +assert_not_has_dir sysroot/boot/loader.0 +assert_has_dir sysroot/boot/loader.1 +assert_has_file sysroot/boot/loader/entries/ostree-3-otheros.conf +assert_has_file sysroot/boot/loader/entries/ostree-2-testos.conf +assert_has_file sysroot/boot/loader/entries/ostree-1-otheros.conf +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok deploy --retain-rollback" + +os_repository_new_commit +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos:testos/buildmaster/x86_64-runtime) +export newrev +assert_not_streq ${rev} ${newrev} + +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS' +# New files in /usr/etc +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/a-new-default-config-file "a new default config file" +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/new-default-dir/moo "a new default dir and file" +# And persist /etc changes from before +assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/aconfigfile +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok upgrade bare" + +os_repository_new_commit +if env OSTREE_EX_STAGE_DEPLOYMENTS=1 ${CMD_PREFIX} ostree admin upgrade --os=testos 2>err.txt; then + fatal "staged when not booted" +fi +echo "ok upgrade failed when staged" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +origrev=${rev} +rev=${newrev} +newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +assert_not_streq ${rev} ${newrev} +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS' +${CMD_PREFIX} ostree admin status +validate_bootloader +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo refs testos:testos > reftest.txt +assert_file_has_content reftest.txt testos:buildmaster/x86_64-runtime + +echo "ok upgrade" + +originfile=$(${CMD_PREFIX} ostree admin --print-current-dir).origin +cp ${originfile} saved-origin +${CMD_PREFIX} ostree admin set-origin --index=0 bacon --set=gpg-verify=false http://tasty.com +assert_file_has_content "${originfile}" "bacon:testos/buildmaster/x86_64-runtime" +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote list -u > remotes.txt +assert_file_has_content remotes.txt 'bacon.*http://tasty\.com' +cp saved-origin ${originfile} +validate_bootloader + +echo "ok set-origin" + +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS' +${CMD_PREFIX} ostree admin undeploy 1 +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS' +assert_not_has_dir sysroot/ostree/deploy/testos/deploy/${rev}.0 + +${CMD_PREFIX} ostree admin undeploy 0 +assert_not_has_dir sysroot/ostree/deploy/testos/deploy/${newrev}.0 +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok undeploy" + +if ${CMD_PREFIX} ostree admin deploy --os=unknown testos:testos/buildmaster/x86_64-runtime; then + assert_not_reached "Unexpected successful deploy of unknown OS" +fi +echo "ok deploy with unknown OS" + +${CMD_PREFIX} ostree admin deploy --os=testos --karg-append=console=/dev/foo --karg-append=console=/dev/bar testos:testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/boot/loader/entries/ostree-4-testos.conf 'console=/dev/foo.*console=/dev/bar' +validate_bootloader + +echo "ok deploy with multiple kernel args" + +origrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +os_repository_new_commit 0 "test upgrade multiple kernel args" +${CMD_PREFIX} ostree admin upgrade --os=testos +newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +assert_not_streq ${origrev} ${newrev} +assert_file_has_content sysroot/boot/loader/entries/ostree-4-testos.conf 'console=/dev/foo.*console=/dev/bar' +validate_bootloader + +echo "ok upgrade with multiple kernel args" + +os_repository_new_commit +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_file_has_content sysroot/boot/loader/entries/ostree-4-testos.conf "^title TestOS 42 ${version} (ostree:testos:0)$" +os_repository_new_commit 0 0 testos/buildmaster/x86_64-runtime 42 +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_file_has_content sysroot/boot/loader/entries/ostree-4-testos.conf "^title TestOS 42 (ostree:testos:0)$" + +echo "ok no duplicate version strings in title" + + +# Test upgrade with and without --override-commit +# See https://github.com/GNOME/ostree/pull/147 +sleep 1 +os_repository_new_commit +# upgrade to the latest +${CMD_PREFIX} ostree admin upgrade --os=testos +head_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime) +prev_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime^) +assert_not_streq ${head_rev} ${prev_rev} +# Don't use `ostree admin status | head -n 1` directly here because `head` +# exiting early might cause SIGPIPE to ostree, which with `set -euo pipefail` +# will cause us to exit. See: https://github.com/ostreedev/ostree/pull/2110. +${CMD_PREFIX} ostree admin status > status-out.txt +head -n 1 < status-out.txt > status.txt +assert_file_has_content status.txt ".* testos ${head_rev}.*" +# now, check that we can't downgrade to an older commit without --allow-downgrade +if ${CMD_PREFIX} ostree admin upgrade --os=testos --override-commit=${prev_rev} 2> err.txt; then + cat err.txt + fatal "downgraded without --allow-downgrade?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +${CMD_PREFIX} ostree admin upgrade --os=testos --override-commit=${prev_rev} --allow-downgrade +${CMD_PREFIX} ostree admin status > status-out.txt +head -n 1 < status-out.txt > status.txt +assert_file_has_content status.txt ".* testos ${prev_rev}.*" +${CMD_PREFIX} ostree admin upgrade --os=testos +${CMD_PREFIX} ostree admin status > status-out.txt +head -n 1 < status-out.txt > status.txt +assert_file_has_content status.txt ".* testos ${head_rev}.*" + +echo "ok upgrade with and without override-commit" + +# check that we can still upgrade to a rev that's not the tip of the branch but +# that's still newer than the deployment +sleep 1 +os_repository_new_commit +sleep 1 +os_repository_new_commit +${CMD_PREFIX} ostree pull --repo=sysroot/ostree/repo --commit-metadata-only --depth=-1 testos:testos/buildmaster/x86_64-runtime +curr_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime) +prev_rev=$(${CMD_PREFIX} ostree rev-parse --repo=sysroot/ostree/repo testos/buildmaster/x86_64-runtime^) +${CMD_PREFIX} ostree admin upgrade --os=testos --override-commit=${prev_rev} +echo "ok upgrade to newer version older than branch tip" + +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string "version=${version}" \ + --add-metadata-string 'ostree.source-title=libtest os_repository_new_commit()' -b testos/buildmaster/x86_64-runtime \ + -s "Build" --tree=dir=${test_tmpdir}/osdata +${CMD_PREFIX} ostree admin upgrade --os=testos +${CMD_PREFIX} ostree admin status | tee status.txt +assert_file_has_content_literal status.txt '`- libtest os_repository_new_commit()' +echo "ok source title" + +deployment=$(${CMD_PREFIX} ostree admin --sysroot=sysroot --print-current-dir) +${CMD_PREFIX} ostree --sysroot=sysroot remote add --set=gpg-verify=false remote-test-physical file://$(pwd)/testos-repo +assert_not_has_file ${deployment}/etc/ostree/remotes.d/remote-test-physical.conf testos-repo +assert_file_has_content sysroot/ostree/repo/config remote-test-physical +echo "ok remote add physical sysroot" + +# Now a hack...symlink ${deployment}/sysroot to the sysroot in lieu of a bind +# mount which we can't do in unit tests. +ln -sr sysroot ${deployment}/sysroot +ln -s sysroot/ostree ${deployment}/ostree +${CMD_PREFIX} ostree --sysroot=${deployment} remote add --set=gpg-verify=false remote-test-nonphysical file://$(pwd)/testos-repo +assert_not_file_has_content sysroot/ostree/repo/config remote-test-nonphysical +assert_file_has_content ${deployment}/etc/ostree/remotes.d/remote-test-nonphysical.conf testos-repo +echo "ok remote add nonphysical sysroot" + +# Test that setting add-remotes-config-dir to false adds a remote in the +# config file rather than the remotes config dir even though this is a +# "system" repo. +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set core.add-remotes-config-dir false +${CMD_PREFIX} ostree --sysroot=${deployment} remote add --set=gpg-verify=false remote-test-config-dir file://$(pwd)/testos-repo +assert_not_has_file ${deployment}/etc/ostree/remotes.d/remote-test-config-dir.conf testos-repo +assert_file_has_content sysroot/ostree/repo/config remote-test-config-dir +echo "ok remote add nonphysical sysroot add-remotes-config-dir false" + +if env OSTREE_SYSROOT_DEBUG="${OSTREE_SYSROOT_DEBUG},test-fifreeze" \ + ${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime 2>err.txt; then + fatal "fifreeze-test exited successfully?" +fi +assert_file_has_content err.txt "fifreeze watchdog was run" +assert_file_has_content err.txt "During fsfreeze-thaw: aborting due to test-fifreeze" +echo "ok fifreeze test" diff --git a/tests/archive-test.sh b/tests/archive-test.sh new file mode 100644 index 0000000..1e63a35 --- /dev/null +++ b/tests/archive-test.sh @@ -0,0 +1,78 @@ +# This file is to be sourced, not executed + +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +$OSTREE checkout test2 checkout-test2 +echo "ok checkout" + +cd checkout-test2 +assert_has_file firstfile +assert_has_file baz/cow +assert_file_has_content baz/cow moo +assert_has_file baz/deeper/ohyeah +echo "ok content" + +cd ${test_tmpdir} +mkdir repo2 +ostree_repo_init repo2 +${CMD_PREFIX} ostree --repo=repo2 pull-local repo +echo "ok local clone" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=repo2 checkout test2 test2-checkout-from-local-clone +cd test2-checkout-from-local-clone +assert_file_has_content baz/cow moo +cd ${test_tmpdir} +rm repo2 -rf +echo "ok local clone checkout" + +$OSTREE checkout -U test2 checkout-user-test2 +echo "ok user checkout" + +cd ${test_tmpdir}/checkout-test2 +$OSTREE commit -b test2-uid0 -s 'UID 0 test' --owner-uid=0 --owner-gid=0 +echo "ok uid0 commit" + +cd ${test_tmpdir} +$OSTREE ls test2-uid0 /firstfile > uid0-ls-output.txt +assert_file_has_content uid0-ls-output.txt "-006[64]4 0 0 6 /firstfile" +echo "ok uid0 ls" + +$OSTREE checkout -U test2-uid0 checkout-user-test2-uid0 +echo "ok user checkout from uid 0" + +cd ${test_tmpdir} +$OSTREE cat test2 /baz/cow > cow-contents +assert_file_has_content cow-contents "moo" +echo "ok cat-file" + +cd ${test_tmpdir} +$OSTREE fsck +echo "ok fsck" + +mkdir -p test-overlays +date > test-overlays/overlaid-file +$OSTREE commit ${COMMIT_ARGS} -b test-base --base test2 --owner-uid 42 --owner-gid 42 test-overlays/ +$OSTREE ls -R test-base > ls.txt +assert_streq "$(wc -l < ls.txt)" 14 +assert_streq "$(grep '42.*42' ls.txt | wc -l)" 2 +echo "ok commit overlay base" diff --git a/tests/basic-test.sh b/tests/basic-test.sh new file mode 100644 index 0000000..fc193f4 --- /dev/null +++ b/tests/basic-test.sh @@ -0,0 +1,1171 @@ +# This file is to be sourced, not executed + +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +echo "1..$((86 + ${extra_basic_tests:-0}))" + +CHECKOUT_U_ARG="" +CHECKOUT_H_ARGS="-H" +COMMIT_ARGS="" +DIFF_ARGS="" +if is_bare_user_only_repo repo; then + # In bare-user-only repos we can only represent files with uid/gid 0, no + # xattrs and canonical permissions, so we need to commit them as such, or + # we end up with repos that don't pass fsck + COMMIT_ARGS="--canonical-permissions" + DIFF_ARGS="--owner-uid=0 --owner-gid=0 --no-xattrs" + # Also, since we can't check out uid=0 files we need to check out in user mode + CHECKOUT_U_ARG="-U" + CHECKOUT_H_ARGS="-U -H" +else + if grep -E -q '^mode=bare-user' repo/config; then + CHECKOUT_H_ARGS="-U -H" + fi +fi + +# This should be dynamic now +assert_not_has_dir repo/uncompressed-objects-cache + +validate_checkout_basic() { + (cd $1; + assert_has_file firstfile + assert_has_file baz/cow + assert_file_has_content baz/cow moo + assert_has_file baz/deeper/ohyeah + assert_symlink_has_content somelink nosuchfile + ) +} + +$OSTREE checkout test2 checkout-test2 +validate_checkout_basic checkout-test2 +if grep -q 'mode=bare$' repo/config; then + assert_not_streq $(stat -c '%h' checkout-test2/firstfile) 1 +fi +echo "ok checkout" + +# Note this tests bare-user *and* bare-user-only +rm checkout-test2 -rf +if grep -q bare-user repo/config; then + $OSTREE checkout -U -H test2 checkout-test2 +else + $OSTREE checkout -H test2 checkout-test2 +fi +validate_checkout_basic checkout-test2 +rm checkout-test2 -rf +# Only do these tests on bare-user/bare, not bare-user-only +# since the latter automatically synthesizes -U if it's not passed. +if ! is_bare_user_only_repo repo; then +if grep -q bare-user repo/config; then + if $OSTREE checkout -H test2 checkout-test2 2>err.txt; then + assert_not_reached "checkout -H worked?" + fi + assert_file_has_content err.txt "User repository.*requires.*user" +else + if $OSTREE checkout -U -H test2 checkout-test2 2>err.txt; then + assert_not_reached "checkout -H worked?" + fi + assert_file_has_content err.txt "Bare repository mode cannot hardlink in user" +fi +fi +echo "ok checkout -H" + +rm checkout-test2 -rf +$OSTREE checkout -C test2 checkout-test2 +for file in firstfile baz/cow baz/alink; do + assert_streq $(stat -c '%h' checkout-test2/$file) 1 +done + +echo "ok checkout -C" + +$OSTREE rev-parse test2 +$OSTREE rev-parse 'test2^' +$OSTREE rev-parse 'test2^^' 2>/dev/null && fatal "rev-parse test2^^ unexpectedly succeeded!" +echo "ok rev-parse" + +checksum=$($OSTREE rev-parse test2) +partial=${checksum:0:6} +echo "partial:" $partial +echo "corresponds to:" $checksum +$OSTREE rev-parse test2 > checksum +$OSTREE rev-parse $partial > partial-results +assert_file_has_content checksum $(cat partial-results) +echo "ok shortened checksum" + +(cd repo && ${CMD_PREFIX} ostree rev-parse test2) +echo "ok repo-in-cwd" + +if ! skip_one_without_user_xattrs; then + rm test-repo -rf + ostree_repo_init test-repo --mode=bare-user + ostree_repo_init test-repo --mode=bare-user + rm test-repo -rf + echo "ok repo-init on existing repo" +fi + +if ! skip_one_without_user_xattrs; then + rm test-repo -rf + ostree_repo_init test-repo --mode=bare-user + ${CMD_PREFIX} ostree --repo=test-repo refs + rm -rf test-repo/tmp + ${CMD_PREFIX} ostree --repo=test-repo refs + assert_has_dir test-repo/tmp + echo "ok autocreate tmp" +fi + +rm checkout-test2 -rf +$OSTREE checkout test2 checkout-test2 +cd checkout-test2 +rm firstfile +$OSTREE commit ${COMMIT_ARGS} -b test2 -s delete + +cd $test_tmpdir +$OSTREE checkout test2 $test_tmpdir/checkout-test2-2 +cd $test_tmpdir/checkout-test2-2 +assert_not_has_file firstfile +assert_has_file baz/saucer +echo "ok removal" + +mkdir -p a/nested/tree +echo one > a/nested/tree/1 +echo two2 > a/nested/2 +echo 3 > a/nested/3 +touch a/4 +echo fivebaby > a/5 +touch a/6 +echo whee > 7 +mkdir -p another/nested/tree +echo anotherone > another/nested/tree/1 +echo whee2 > another/whee +# FIXME - remove grep for . +$OSTREE commit ${COMMIT_ARGS} -b test2 -s "Another commit" +echo "ok commit" + +cd ${test_tmpdir} +$OSTREE checkout test2 $test_tmpdir/checkout-test2-3 +cd checkout-test2-3 +assert_has_file a/nested/2 +assert_file_has_content a/nested/2 'two2' +echo "ok stdin contents" + +cd ${test_tmpdir}/checkout-test2-3 +echo 4 > four +mkdir -p yet/another/tree +echo leaf > yet/another/tree/green +echo helloworld > yet/message +rm a/5 +$OSTREE commit ${COMMIT_ARGS} -b test2 -s "Current directory" +echo "ok cwd commit" + +cd ${test_tmpdir} +$OSTREE checkout test2 $test_tmpdir/checkout-test2-4 +cd checkout-test2-4 +assert_file_has_content yet/another/tree/green 'leaf' +assert_file_has_content four '4' +echo "ok cwd contents" + +cd ${test_tmpdir} +rm checkout-test2-l -rf +$OSTREE checkout ${CHECKOUT_H_ARGS} test2 $test_tmpdir/checkout-test2-l +date > $test_tmpdir/checkout-test2-l/newdatefile.txt +$OSTREE commit ${COMMIT_ARGS} --link-checkout-speedup --consume -b test2 --tree=dir=$test_tmpdir/checkout-test2-l +assert_not_has_dir $test_tmpdir/checkout-test2-l +$OSTREE fsck +# Some of the later tests are sensitive to state +$OSTREE reset test2 test2^ +$OSTREE prune --refs-only +echo "ok consume (nom nom nom)" + +# Test adopt +cd ${test_tmpdir} +rm checkout-test2-l -rf +$OSTREE checkout ${CHECKOUT_H_ARGS} test2 $test_tmpdir/checkout-test2-l +echo 'a file to consume 🍔' > $test_tmpdir/checkout-test2-l/eatme.txt +# Save a link to it for device/inode comparison +ln $test_tmpdir/checkout-test2-l/eatme.txt $test_tmpdir/eatme-savedlink.txt +$OSTREE commit ${COMMIT_ARGS} --link-checkout-speedup --consume -b test2 --tree=dir=$test_tmpdir/checkout-test2-l +$OSTREE fsck +# Adoption isn't implemented for bare-user yet +eatme_objpath=$(ostree_file_path_to_object_path repo test2 /eatme.txt) +if grep -q '^mode=bare$' repo/config || is_bare_user_only_repo repo; then + assert_files_hardlinked ${test_tmpdir}/eatme-savedlink.txt ${eatme_objpath} +else + if files_are_hardlinked ${test_tmpdir}/eatme-savedlink.txt ${eatme_objpath}; then + fatal "bare-user adopted?" + fi +fi +assert_not_has_dir $test_tmpdir/checkout-test2-l +# Some of the later tests are sensitive to state +$OSTREE reset test2 test2^ +$OSTREE prune --refs-only +rm -f ${test_tmpdir}/eatme-savedlink.txt +echo "ok adopt" + +cd ${test_tmpdir} +$OSTREE commit ${COMMIT_ARGS} -b test2-no-parent -s '' $test_tmpdir/checkout-test2-4 +assert_streq $($OSTREE log test2-no-parent |grep '^commit' | wc -l) "1" +$OSTREE commit ${COMMIT_ARGS} -b test2-no-parent -s '' --parent=none $test_tmpdir/checkout-test2-4 +assert_streq $($OSTREE log test2-no-parent |grep '^commit' | wc -l) "1" +echo "ok commit no parent" + +cd ${test_tmpdir} +# Do the --bind-ref=, so we store both branches sorted +# in metadata and thus the checksums remain the same. +empty_rev=$($OSTREE commit ${COMMIT_ARGS} -b test2-no-subject --bind-ref=test2-no-subject-2 -s '' --timestamp="2005-10-29 12:43:29 +0000" $test_tmpdir/checkout-test2-4) +omitted_rev=$($OSTREE commit ${COMMIT_ARGS} -b test2-no-subject-2 --bind-ref=test2-no-subject --timestamp="2005-10-29 12:43:29 +0000" $test_tmpdir/checkout-test2-4) +assert_streq $empty_rev $omitted_rev +echo "ok commit no subject" + +cd ${test_tmpdir} +cat >commitmsg.txt < log.txt +assert_file_has_content log.txt '^ *This is a long$' +assert_file_has_content log.txt '^ *Build-Host:.*example\.com$' +assert_file_has_content log.txt '^ *Crunchy-With.*true$' +$OSTREE refs --delete branch-with-commitmsg +echo "ok commit body file" + +cd ${test_tmpdir} +$OSTREE commit ${COMMIT_ARGS} -b test2-custom-parent -s '' $test_tmpdir/checkout-test2-4 +$OSTREE commit ${COMMIT_ARGS} -b test2-custom-parent -s '' $test_tmpdir/checkout-test2-4 +$OSTREE commit ${COMMIT_ARGS} -b test2-custom-parent -s '' $test_tmpdir/checkout-test2-4 +assert_streq $($OSTREE log test2-custom-parent |grep '^commit' | wc -l) "3" +prevparent=$($OSTREE rev-parse test2-custom-parent^) +$OSTREE commit ${COMMIT_ARGS} -b test2-custom-parent -s '' --parent=${prevparent} $test_tmpdir/checkout-test2-4 +assert_streq $($OSTREE log test2-custom-parent |grep '^commit' | wc -l) "3" +echo "ok commit custom parent" + +cd ${test_tmpdir} +orphaned_rev=$($OSTREE commit ${COMMIT_ARGS} --orphan -s "$(date)" $test_tmpdir/checkout-test2-4) +$OSTREE ls ${orphaned_rev} >/dev/null +$OSTREE prune --refs-only +if $OSTREE ls ${orphaned_rev} 2>err.txt; then + assert_not_reached "Found orphaned commit" +fi +assert_file_has_content err.txt "No such metadata object" +echo "ok commit orphaned" + +cd ${test_tmpdir} +# in bare-user-only mode, we canonicalize ownership to 0:0, so checksums won't +# match -- we could add a --ignore-ownership option I suppose? +if is_bare_user_only_repo repo; then + echo "ok # SKIP checksums won't match up in bare-user-only" +else + $OSTREE fsck + CHECKSUM_FLAG= + if [ -n "${OSTREE_NO_XATTRS:-}" ]; then + CHECKSUM_FLAG=--ignore-xattrs + fi + rm -rf checksum-test + $OSTREE checkout test2 checksum-test + find checksum-test/ -type f | while read fn; do + checksum=$($CMD_PREFIX ostree checksum $CHECKSUM_FLAG $fn) + objpath=repo/objects/${checksum::2}/${checksum:2}.file + assert_has_file $objpath + # running `ostree checksum` on the obj might not necessarily match, let's + # just check that they have the same content to confirm that it's + # (probably) the originating file + object_content_checksum=$(sha256sum $objpath | cut -f1 -d' ') + checkout_content_checksum=$(sha256sum $fn | cut -f1 -d' ') + assert_streq "$object_content_checksum" "$checkout_content_checksum" + done + echo "ok checksum CLI" +fi + +cd ${test_tmpdir} +$OSTREE diff test2^ test2 > diff-test2 +assert_file_has_content diff-test2 'D */a/5' +assert_file_has_content diff-test2 'A */yet$' +assert_file_has_content diff-test2 'A */yet/message$' +assert_file_has_content diff-test2 'A */yet/another/tree/green$' +echo "ok diff revisions" + +cd ${test_tmpdir}/checkout-test2-4 +echo afile > oh-look-a-file +$OSTREE diff test2 ./ > ${test_tmpdir}/diff-test2-2 +rm oh-look-a-file +cd ${test_tmpdir} +assert_file_has_content diff-test2-2 'A *oh-look-a-file$' +echo "ok diff cwd" + +cd ${test_tmpdir}/checkout-test2-4 +$OSTREE diff ${DIFF_ARGS} test2 ./ > ${test_tmpdir}/diff-test2 +assert_file_empty ${test_tmpdir}/diff-test2 +$OSTREE diff ${DIFF_ARGS} test2 --owner-uid=$((`id -u`+1)) ./ > ${test_tmpdir}/diff-test2 +assert_file_has_content ${test_tmpdir}/diff-test2 'M */yet$' +assert_file_has_content ${test_tmpdir}/diff-test2 'M */yet/message$' +assert_file_has_content ${test_tmpdir}/diff-test2 'M */yet/another/tree/green$' +echo "ok diff file with different uid" + +$OSTREE diff ${DIFF_ARGS} test2 --owner-gid=$((`id -g`+1)) ./ > ${test_tmpdir}/diff-test2 +assert_file_has_content ${test_tmpdir}/diff-test2 'M */yet$' +assert_file_has_content ${test_tmpdir}/diff-test2 'M */yet/message$' +assert_file_has_content ${test_tmpdir}/diff-test2 'M */yet/another/tree/green$' +echo "ok diff file with different gid" + +cd ${test_tmpdir}/checkout-test2-4 +rm four +mkdir four +touch four/other +$OSTREE diff test2 ./ > ${test_tmpdir}/diff-test2-2 +cd ${test_tmpdir} +assert_file_has_content diff-test2-2 'M */four$' +echo "ok diff file changing type" + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + mkdir repo2 + # Use a different mode to test hardlinking metadata only + if grep -q 'mode=archive' repo/config || is_bare_user_only_repo repo; then + opposite_mode=bare-user + else + opposite_mode=archive + fi + ostree_repo_init repo2 --mode=$opposite_mode + ${CMD_PREFIX} ostree --repo=repo2 pull-local repo >out.txt + assert_file_has_content out.txt "[1-9][0-9]* metadata, [1-9][0-9]* content objects imported" + test2_commitid=$(${CMD_PREFIX} ostree --repo=repo rev-parse test2) + test2_commit_relpath=/objects/${test2_commitid:0:2}/${test2_commitid:2}.commit + assert_files_hardlinked repo/${test2_commit_relpath} repo2/${test2_commit_relpath} + echo "ok pull-local (hardlinking metadata)" +fi + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + rm repo2 -rf && mkdir repo2 + ostree_repo_init repo2 --mode=$opposite_mode + ${CMD_PREFIX} ostree --repo=repo2 pull-local --bareuseronly-files repo test2 + ${CMD_PREFIX} ostree --repo=repo2 fsck -q + echo "ok pull-local --bareuseronly-files" +fi + +rm repo2 -rf +ostree_repo_init repo2 --mode="$mode" +$CMD_PREFIX ostree --repo=repo2 pull-local --untrusted repo test2 +target_file_object=$(ostree_file_path_to_relative_object_path repo test2 baz/saucer) +target_file_checksum=$(ostree_file_path_to_checksum repo test2 baz/saucer) +assert_files_hardlinked repo{,2}/${target_file_object} +echo "ok pull-local hardlinking, untrusted" + +if grep -q 'mode=bare' repo/config; then + # Now copy/corrupt an object in a 3rd repo, pull into 2nd (leaving the first pristine) + rm repo{2,3} -rf + ostree_repo_init repo2 --mode="$mode" + ostree_repo_init repo3 --mode="$mode" + # Pull into 3rd repo, corrupt an object + $CMD_PREFIX ostree --repo=repo3 pull-local repo test2 + cp -a --reflink=auto repo3/${target_file_object}{,.tmp} + mv repo3/${target_file_object}{.tmp,} + echo blah >> repo3/${target_file_object} + if $CMD_PREFIX ostree --repo=repo2 pull-local --untrusted repo3 2>err.txt; then + assert_not_reached "pulled --untrusted from corrupted repo" + fi + assert_file_has_content err.txt 'Corrupted.*'${target_file_checksum} + rm -f err.txt + # But this one should succeed + $CMD_PREFIX ostree --repo=repo2 pull-local repo3 + if $CMD_PREFIX ostree --repo=repo2 fsck 2>err.txt; then + fatal "repo should have pulled corrupted object" + fi + assert_file_has_content err.txt 'Corrupted.*'${target_file_checksum} +fi +echo "ok pull-local --untrusted corruption" +rm repo{2,3} -rf + +# This is mostly a copy of the suid test in test-basic-user-only.sh, +# but for the `pull --bareuseronly-files` case. +cd ${test_tmpdir} +rm repo-input -rf +ostree_repo_init repo-input init --mode=archive +cd ${test_tmpdir} +cat > statoverride.txt < files/some-setuid +chmod 0644 files/some-setuid +$CMD_PREFIX ostree --repo=repo-input commit -b content-with-suid --statoverride=statoverride.txt --tree=dir=files +if $CMD_PREFIX ostree pull-local --repo=repo --bareuseronly-files repo-input content-with-suid 2>err.txt; then + assert_not_reached "copying suid file with --bareuseronly-files worked?" +fi +assert_file_has_content err.txt 'Content object.*: invalid mode.*with bits 040.*' +echo "ok pull-local (bareuseronly files)" + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + ${CMD_PREFIX} ostree --repo=repo checkout ${CHECKOUT_U_ARG} test2 test2-checkout-from-local-clone + cd test2-checkout-from-local-clone + assert_file_has_content yet/another/tree/green 'leaf' + echo "ok local clone checkout" +fi + +$OSTREE checkout -U test2 checkout-user-test2 +echo "ok user checkout" + +$OSTREE commit ${COMMIT_ARGS} -b test2 -s "Another commit" --tree=ref=test2 +echo "ok commit from ref" + +$OSTREE commit ${COMMIT_ARGS} -b test2 -s "Another commit with modifier" --tree=ref=test2 --owner-uid=`id -u` +echo "ok commit from ref with modifier" + +$OSTREE commit ${COMMIT_ARGS} -b trees/test2 -s 'ref with / in it' --tree=ref=test2 +echo "ok commit ref with /" + +mkdir badutf8 +echo "invalid utf8 filename" > badutf8/$(printf '\x80') +if $OSTREE commit ${COMMIT_ARGS} -b badutf8 --tree=dir=badutf8 2>err.txt; then + assert_not_reached "commit filename with invalid UTF-8" +fi +assert_file_has_content err.txt "Invalid UTF-8 in filename" +echo "ok commit bad UTF-8" + +old_rev=$($OSTREE rev-parse test2) +$OSTREE ls -R -C test2 +$OSTREE commit ${COMMIT_ARGS} --skip-if-unchanged -b trees/test2 -s 'should not be committed' --tree=ref=test2 +$OSTREE ls -R -C test2 +new_rev=$($OSTREE rev-parse test2) +assert_streq "${old_rev}" "${new_rev}" +echo "ok commit --skip-if-unchanged" + +cd ${test_tmpdir}/checkout-test2-4 +$OSTREE commit ${COMMIT_ARGS} -b test2 -s "no xattrs" --no-xattrs +echo "ok commit with no xattrs" + +mkdir tree-A tree-B +touch tree-A/file-a tree-B/file-b + +$OSTREE commit ${COMMIT_ARGS} -b test3-1 -s "Initial tree" --tree=dir=tree-A +$OSTREE commit ${COMMIT_ARGS} -b test3-2 -s "Replacement tree" --tree=dir=tree-B +$OSTREE commit ${COMMIT_ARGS} -b test3-combined -s "combined tree" --tree=ref=test3-1 --tree=ref=test3-2 + +$OSTREE checkout test3-combined checkout-test3-combined + +assert_has_file checkout-test3-combined/file-a +assert_has_file checkout-test3-combined/file-b + +mkdir -p tree-C/usr/share tree-C/usr/bin tree-C/etc tree-D/etc + +echo exe >tree-C/usr/bin/exe +echo sudoers1 >tree-C/etc/sudoers +echo mtab >tree-C/etc/mtab + +echo sudoers2 >tree-D/etc/sudoers + +$OSTREE commit ${COMMIT_ARGS} -b test3-C1 --tree=dir=tree-C +$OSTREE commit ${COMMIT_ARGS} -b test3-D --tree=dir=tree-D + +echo sudoers2 >tree-C/etc/sudoers +$OSTREE commit ${COMMIT_ARGS} -b test3-C2 --tree=dir=tree-C +echo sudoers1 >tree-C/etc/sudoers + +$OSTREE commit ${COMMIT_ARGS} -b test3-ref-ref --tree=ref=test3-C1 --tree=ref=test3-D +$OSTREE commit ${COMMIT_ARGS} -b test3-dir-ref --tree=dir=tree-C --tree=ref=test3-D +$OSTREE commit ${COMMIT_ARGS} -b test3-ref-dir --tree=ref=test3-C1 --tree=dir=tree-D +$OSTREE commit ${COMMIT_ARGS} -b test3-dir-dir --tree=dir=tree-C --tree=dir=tree-D + +assert_trees_identical() { + $OSTREE diff "$1" "$2" > "diff-$1-$2" + cat "diff-$1-$2" 1>&2 + assert_file_empty "diff-$1-$2" + rm "diff-$1-$2" +} + +for x in ref dir +do + for y in ref dir + do + assert_trees_identical test3-C2 "test3-$x-$y" + done +done + +# Regression test + +mkdir -p tree-E/etc +mkdir -p tree-F/etc/apt/sources.list.d/ +echo contents >tree-F/etc/apt/sources.list.d/universe.list + +$OSTREE commit ${COMMIT_ARGS} -b test3-E --tree=dir=tree-E +$OSTREE commit ${COMMIT_ARGS} -b test3-F --tree=dir=tree-F + +$OSTREE commit ${COMMIT_ARGS} -b test3-F2 --tree=ref=test3-E --tree=ref=test3-F + +assert_trees_identical test3-F test3-F2 + +echo "ok commit combined ref trees" + +# NB: The + is optional, but we need to make sure we support it +cd ${test_tmpdir} +cat > test-statoverride.txt < a/readable-only +chmod 664 a/readable-only +$OSTREE commit ${COMMIT_ARGS} -b test2-override -s "with statoverride" --statoverride=../test-statoverride.txt +cd ${test_tmpdir} +$OSTREE checkout test2-override checkout-test2-override +if ! is_bare_user_only_repo repo; then + test -g checkout-test2-override/a/nested/2 + test -u checkout-test2-override/a/nested/3 +else + test '!' -g checkout-test2-override/a/nested/2 + test '!' -u checkout-test2-override/a/nested/3 +fi +assert_file_has_mode checkout-test2-override/a/readable-only 600 +echo "ok commit statoverride" + +cd ${test_tmpdir} +rm test2-checkout -rf +$OSTREE checkout test2 test2-checkout +cd test2-checkout +install -m 0755 /dev/null user-wx +install -m 0575 /dev/null group-wx +install -m 0775 /dev/null both-wx +install -m 0555 /dev/null ugox +install -m 0644 /dev/null user-writable +cd .. +$OSTREE commit ${COMMIT_ARGS} -b test2-w-xor-x --mode-ro-executables --tree=dir=test2-checkout +$OSTREE ls test2-w-xor-x > ls.txt +for x in /{user,group,both}-wx; do + assert_file_has_content ls.txt '^-00555 .*'$x +done +assert_file_has_content ls.txt '^-00644 .*/user-writable' +echo "ok commit --mode-ro-executables" + +cd ${test_tmpdir} +cat > test-skiplist.txt </dev/null 2>err.txt; then + fatal "listed refs without remotes dir?" +fi +assert_file_has_content err.txt 'Listing refs.*opendir.*No such file or directory' +mv repo/refs/remotes{.orig,} +$OSTREE refs --list >/dev/null +echo "ok refs enoent error" + +cd ${test_tmpdir} +# Verify we can't cat dirs +for path in / /baz; do + if $OSTREE cat test2 $path 2>err.txt; then + assert_not_reached "cat directory" + fi + assert_file_has_content err.txt "open directory" +done +rm checkout-test2 -rf +$OSTREE cat test2 /yet/another/tree/green > greenfile-contents +assert_file_has_content greenfile-contents "leaf" +$OSTREE checkout test2 checkout-test2 +ls -alR checkout-test2 +ln -sr checkout-test2/{four,four-link} +ln -sr checkout-test2/{baz/cow,cow-link} +ln -sr checkout-test2/{cow-link,cow-link-link} +$OSTREE commit -b test2-withlink --tree=dir=checkout-test2 +if $OSTREE cat test2-withlink /four-link 2>err.txt; then + assert_not_reached "cat directory" +fi +assert_file_has_content err.txt "open directory" +for path in /cow-link /cow-link-link; do + $OSTREE cat test2-withlink $path >contents.txt + assert_file_has_content contents.txt moo +done +echo "ok cat-file" + +cd ${test_tmpdir} +$OSTREE checkout --subpath /yet/another test2 checkout-test2-subpath +cd checkout-test2-subpath +assert_file_has_content tree/green "leaf" +cd ${test_tmpdir} +rm checkout-test2-subpath -rf +$OSTREE ls -R test2 +# Test checking out a file +$OSTREE checkout --subpath /baz/saucer test2 checkout-test2-subpath +assert_file_has_content checkout-test2-subpath/saucer alien +# Test checking out a file without making a subdir +mkdir t +cd t +$OSTREE checkout --subpath /baz/saucer test2 . +assert_file_has_content saucer alien +rm t -rf +echo "ok checkout subpath" + +cd ${test_tmpdir} +rm -rf checkout-test2-skiplist +cat > test-skiplist.txt < test-skiplist.txt < union-files-count +$OSTREE checkout --union test2 checkout-test2-union +find checkout-test2-union | wc -l > union-files-count.new +cmp union-files-count{,.new} +cd checkout-test2-union +assert_file_has_content ./yet/another/tree/green "leaf" +echo "ok checkout union 1" + +cd ${test_tmpdir} +$OSTREE commit ${COMMIT_ARGS} -b test-union-add --tree=ref=test2 +$OSTREE checkout test-union-add checkout-test-union-add +echo 'file for union add testing' > checkout-test-union-add/union-add-test +echo 'another file for union add testing' > checkout-test-union-add/union-add-test2 +$OSTREE commit ${COMMIT_ARGS} -b test-union-add --tree=dir=checkout-test-union-add +rm checkout-test-union-add -rf +# Check out previous +$OSTREE checkout test-union-add^ checkout-test-union-add +assert_not_has_file checkout-test-union-add/union-add-test +assert_not_has_file checkout-test-union-add/union-add-test2 +# Now create a file we don't want overwritten +echo 'existing file for union add' > checkout-test-union-add/union-add-test +$OSTREE checkout --union-add test-union-add checkout-test-union-add +assert_file_has_content checkout-test-union-add/union-add-test 'existing file for union add' +assert_file_has_content checkout-test-union-add/union-add-test2 'another file for union add testing' +echo "ok checkout union add" + +# Test --union-identical +# Prepare data: +cd ${test_tmpdir} +for x in $(seq 3); do + mkdir -p pkg${x}/usr/{bin,share/licenses} + # Separate binaries and symlinks + echo 'binary for pkg'${x} > pkg${x}/usr/bin/pkg${x} + ln -s pkg${x} pkg${x}/usr/bin/link${x} + # But they share the GPL + echo 'this is the GPL' > pkg${x}/usr/share/licenses/COPYING + ln -s COPYING pkg${x}/usr/share/licenses/LICENSE + $OSTREE commit -b union-identical-pkg${x} --tree=dir=pkg${x} +done +rm union-identical-test -rf +for x in $(seq 3); do + $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-pkg${x} union-identical-test +done +if $OSTREE checkout ${CHECKOUT_H_ARGS/-H/} --union-identical union-identical-pkg${x} union-identical-test-tmp 2>err.txt; then + fatal "--union-identical without -H" +fi +assert_file_has_content err.txt "error:.*--union-identical requires --require-hardlinks" +for x in $(seq 3); do + for v in pkg link; do + assert_file_has_content union-identical-test/usr/bin/${v}${x} "binary for pkg"${x} + done + for v in COPYING LICENSE; do + assert_file_has_content union-identical-test/usr/share/licenses/${v} GPL + done +done +# now checkout the first pkg in force copy mode to make sure we can checksum +rm union-identical-test -rf +$OSTREE checkout --force-copy union-identical-pkg1 union-identical-test +for x in 2 3; do + $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-pkg${x} union-identical-test +done +echo "ok checkout union identical merges" + +# Make conflicting packages, one with regfile, one with symlink +mkdir -p pkg-conflict1bin/usr/{bin,share/licenses} +echo 'binary for pkg-conflict1bin' > pkg-conflict1bin/usr/bin/pkg1 +echo 'this is the GPL' > pkg-conflict1bin/usr/share/licenses/COPYING +$OSTREE commit -b union-identical-conflictpkg1bin --tree=dir=pkg-conflict1bin +mkdir -p pkg-conflict1link/usr/{bin,share/licenses} +ln -s somewhere-else > pkg-conflict1link/usr/bin/pkg1 +echo 'this is the GPL' > pkg-conflict1link/usr/share/licenses/COPYING +$OSTREE commit -b union-identical-conflictpkg1link --tree=dir=pkg-conflict1link + +for v in bin link; do + rm union-identical-test -rf + $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-pkg1 union-identical-test + if $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-conflictpkg1${v} union-identical-test 2>err.txt; then + fatal "union identical $v succeeded?" + fi + assert_file_has_content err.txt 'error:.*File exists' +done +echo "ok checkout union identical conflicts" + +cd ${test_tmpdir} +rm files -rf && mkdir files +touch files/anemptyfile +touch files/anotheremptyfile +$CMD_PREFIX ostree --repo=repo commit --consume -b tree-with-empty-files --tree=dir=files +$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} -z tree-with-empty-files tree-with-empty-files +if files_are_hardlinked tree-with-empty-files/an{,other}emptyfile; then + fatal "--force-copy-zerosized failed" +fi +rm tree-with-empty-files -rf +$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} tree-with-empty-files tree-with-empty-files +assert_files_hardlinked tree-with-empty-files/an{,other}emptyfile +rm tree-with-empty-files -rf +echo "ok checkout --force-copy-zerosized" + +# These should merge, they're identical +$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files +$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files +echo notempty > tree-with-empty-files/anemptyfile.new && mv tree-with-empty-files/anemptyfile{.new,} +$CMD_PREFIX ostree --repo=repo commit --consume -b tree-with-conflicting-empty-files --tree=dir=tree-with-empty-files +# Reset back to base +rm tree-with-empty-files -rf +$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files +if $CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-conflicting-empty-files tree-with-empty-files 2>err.txt; then + fatal "--union-identical --force-copy-zerosized unexpectedly succeeded with non-identical files" +fi +assert_file_has_content err.txt 'error:.*File exists' +echo "ok checkout --union-identical --force-copy-zerosized" + +cd ${test_tmpdir} +rm files -rf && mkdir files +mkdir files/worldwritable-dir +chmod a+w files/worldwritable-dir +$CMD_PREFIX ostree --repo=repo commit -b content-with-dir-world-writable --tree=dir=files +rm dir-co -rf +$CMD_PREFIX ostree --repo=repo checkout -U -H -M content-with-dir-world-writable dir-co +assert_file_has_mode dir-co/worldwritable-dir 775 +if ! is_bare_user_only_repo repo; then + rm dir-co -rf + $CMD_PREFIX ostree --repo=repo checkout -U -H content-with-dir-world-writable dir-co + assert_file_has_mode dir-co/worldwritable-dir 777 +fi +rm dir-co -rf +echo "ok checkout bareuseronly dir" + +cd ${test_tmpdir} +rm -rf shadow-repo +mkdir shadow-repo +ostree_repo_init shadow-repo +${CMD_PREFIX} ostree --repo=shadow-repo config set core.parent $(pwd)/repo +rm -rf test2-checkout +parent_rev_test2=$(${CMD_PREFIX} ostree --repo=repo rev-parse test2) +${CMD_PREFIX} ostree --repo=shadow-repo checkout ${CHECKOUT_U_ARG} "${parent_rev_test2}" test2-checkout +echo "ok checkout from shadow repo" + +cd ${test_tmpdir} +if $OSTREE checkout test2 --subpath /enoent 2>err.txt; then + assert_not_reached "checking outnonexistent file unexpectedly succeeded!" +fi +assert_file_has_content err.txt 'No such file or directory' +echo "ok subdir enoent" + +cd ${test_tmpdir} +$OSTREE checkout test2 --allow-noent --subpath /enoent 2>/dev/null +echo "ok subdir noent" + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + mkdir repo4 + ostree_repo_init repo4 --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo4 pull-local --commit-metadata-only repo test2 + csum1=$($OSTREE rev-parse test2) + csum2=$(${CMD_PREFIX} ostree --repo=repo4 rev-parse test2) + assert_streq "${csum1}" "${csum2}" + test -f repo4/state/$csum1.commitpartial + echo "ok pull-local --commit-metadata-only" + rm -rf repo4 +fi + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + ostree_repo_init repo3 --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo3 pull-local --remote=aremote repo test2 + ${CMD_PREFIX} ostree --repo=repo3 rev-parse aremote/test2 + echo "ok pull-local with --remote arg" +fi + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + ${CMD_PREFIX} ostree --repo=repo3 prune + find repo3/objects -name '*.commit' > objlist-before-prune + rm repo3/refs/heads/* repo3/refs/mirrors/* repo3/refs/remotes/* -rf + ${CMD_PREFIX} ostree --repo=repo3 prune --refs-only + find repo3/objects -name '*.commit' > objlist-after-prune + if cmp -s objlist-before-prune objlist-after-prune; then + fatal "Prune didn't delete anything!" + fi + rm repo3 objlist-before-prune objlist-after-prune -rf + echo "ok prune" +fi + +cd ${test_tmpdir} +rm repo3 -rf +ostree_repo_init repo3 --mode=archive +${CMD_PREFIX} ostree --repo=repo3 pull-local --remote=aremote repo test2 +rm repo3/refs/remotes -rf +mkdir repo3/refs/remotes +${CMD_PREFIX} ostree --repo=repo3 prune --refs-only +find repo3/objects -name '*.filez' > file-objects +if test -s file-objects; then + assert_not_reached "prune didn't delete all objects" +fi +echo "ok prune in archive deleted everything" + +cd ${test_tmpdir} +rm -rf test2-checkout +$OSTREE checkout test2 test2-checkout +(cd test2-checkout && $OSTREE commit ${COMMIT_ARGS} --link-checkout-speedup -b test2 -s "tmp") +echo "ok commit with link speedup" + +cd ${test_tmpdir} +rm -rf test2-checkout +$OSTREE checkout test2 test2-checkout +# set cow to different perms, but re-set cowro to the same perms +cat > statoverride.txt < stats.txt +$OSTREE diff test2 test2-tmp > diff-test2 +assert_file_has_content diff-test2 'M */baz/cow$' +assert_not_file_has_content diff-test2 'M */baz/cowro$' +assert_not_file_has_content diff-test2 'baz/saucer' +# only /baz/cow is a cache miss +assert_file_has_content stats.txt '^Content Written: 1$' +echo "ok commit with link speedup and modifier" + +cd ${test_tmpdir} +$OSTREE ls test2 +echo "ok ls with no argument" + +cd ${test_tmpdir} +if $OSTREE ls test2 /baz/cow/notadir 2>errmsg; then + assert_not_reached +fi +assert_file_has_content errmsg "Not a directory" +echo "ok ls of not a directory" + +cd ${test_tmpdir} +$OSTREE show test2 +echo "ok show with non-checksum" + +cd $test_tmpdir/checkout-test2 +checksum=$($OSTREE commit ${COMMIT_ARGS} -b test4 -s "Third commit") +cd ${test_tmpdir} +$OSTREE show test4 > show-output +assert_file_has_content show-output "Third commit" +assert_file_has_content show-output "commit $checksum" +echo "ok show full output" + +grep -E -e '^ContentChecksum' show-output > previous-content-checksum.txt +cd $test_tmpdir/checkout-test2 +checksum=$($OSTREE commit ${COMMIT_ARGS} -b test4 -s "Another commit with different subject") +cd ${test_tmpdir} +$OSTREE show test4 | grep -E -e '^ContentChecksum' > new-content-checksum.txt +if ! diff -u previous-content-checksum.txt new-content-checksum.txt; then + fatal "content checksum differs" +fi +echo "ok content checksum" + +cd $test_tmpdir/checkout-test2 +checksum1=$($OSTREE commit ${COMMIT_ARGS} -b test5 -s "First commit") +checksum2=$($OSTREE commit ${COMMIT_ARGS} -b test5 -s "Second commit") +cd ${test_tmpdir} +$OSTREE log test5 > log-output +assert_file_has_content log-output "First commit" +assert_file_has_content log-output "commit $checksum1" +assert_file_has_content log-output "Second commit" +assert_file_has_content log-output "commit $checksum2" +echo "ok log output" + +cd $test_tmpdir/checkout-test2 +checksum1=$($OSTREE commit ${COMMIT_ARGS} -b test6 -s "First commit") +checksum2=$($OSTREE commit ${COMMIT_ARGS} -b test6 -s "Second commit") +cd ${test_tmpdir} +$OSTREE show test6 > show-output +assert_file_has_content show-output "commit $checksum2" +$OSTREE reset test6 $checksum1 +$OSTREE show test6 > show-output +assert_file_has_content show-output "commit $checksum1" +echo "ok basic reset" + +cd ${test_tmpdir} +rm checkout-test2 -rf +$OSTREE checkout test2 checkout-test2 +touch checkout-test2/sometestfile +$OSTREE commit ${COMMIT_ARGS} -s sometest -b test2 checkout-test2 +echo "ok commit with directory filename" + +cd $test_tmpdir/checkout-test2 +$OSTREE commit ${COMMIT_ARGS} -b test2 -s "Metadata string" --add-metadata-string=FOO=BAR \ + --add-metadata-string=KITTENS=CUTE --add-detached-metadata-string=SIGNATURE=HANCOCK \ + --add-metadata=SOMENUM='uint64 42' --tree=ref=test2 +cd ${test_tmpdir} +$OSTREE show --print-metadata-key=FOO test2 > test2-meta +assert_file_has_content test2-meta "BAR" +$OSTREE show --print-metadata-key=KITTENS test2 > test2-meta +assert_file_has_content test2-meta "CUTE" + +$OSTREE show --print-metadata-key=SOMENUM test2 > test2-meta +case "$("${test_builddir}/get-byte-order")" in + (4321) + assert_file_has_content test2-meta "uint64 42" + ;; + (1234) + assert_file_has_content test2-meta "uint64 3026418949592973312" + ;; + (*) + fatal "neither little-endian nor big-endian?" + ;; +esac + +$OSTREE show -B --print-metadata-key=SOMENUM test2 > test2-meta +assert_file_has_content test2-meta "uint64 42" +$OSTREE show --print-detached-metadata-key=SIGNATURE test2 > test2-meta +assert_file_has_content test2-meta "HANCOCK" +echo "ok metadata commit with strings" + +$OSTREE commit ${COMMIT_ARGS} -b test2 --tree=ref=test2 \ + --add-detached-metadata-string=SIGNATURE=HANCOCK \ + --keep-metadata=KITTENS --keep-metadata=SOMENUM +if $OSTREE show --print-metadata-key=FOO test2; then + assert_not_reached "FOO was kept without explicit --keep-metadata?" +fi +$OSTREE show --print-metadata-key=KITTENS test2 > test2-meta +assert_file_has_content test2-meta "CUTE" +$OSTREE show -B --print-metadata-key=SOMENUM test2 > test2-meta +assert_file_has_content test2-meta "uint64 42" +echo "ok keep metadata from parent" + +cd ${test_tmpdir} +$OSTREE show --print-metadata-key=ostree.ref-binding test2 > test2-ref-binding +assert_file_has_content test2-ref-binding 'test2' + +$OSTREE commit ${COMMIT_ARGS} -b test2-unbound --no-bindings --tree=dir=${test_tmpdir}/checkout-test2 +if $OSTREE show --print-metadata-key=ostree.ref-binding test2-unbound; then + fatal "ref bindings found with --no-bindings?" +fi +echo "ok refbinding" + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + rm repo2 -rf + mkdir repo2 + ostree_repo_init repo2 --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo2 pull-local repo + ${CMD_PREFIX} ostree --repo=repo2 show --print-detached-metadata-key=SIGNATURE test2 > test2-meta + assert_file_has_content test2-meta "HANCOCK" + echo "ok pull-local after commit metadata" +fi + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=repo remote --set=tls-permissive=true add aremote http://remote.example.com/repo testos/buildmaster/x86_64-runtime +assert_file_has_content repo/config 'tls-permissive=true' +assert_file_has_content repo/config 'remote\.example\.com' +echo "ok remote add with set" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=repo remote show-url aremote > aremote-url.txt +assert_file_has_content aremote-url.txt 'http.*remote\.example\.com/repo' +echo "ok remote show-url" + +cd ${test_tmpdir} +rm -rf test2-checkout +if grep bare-user repo/config; then + $OSTREE checkout -U test2 test2-checkout +else + $OSTREE checkout test2 test2-checkout +fi +stat '--format=%Y' test2-checkout/baz/cow > cow-mtime +assert_file_has_content cow-mtime 0 +stat '--format=%Y' test2-checkout/baz/deeper > deeper-mtime +assert_file_has_content deeper-mtime 0 +echo "ok content mtime" + +cd ${test_tmpdir} +rm repo2 -rf +mkdir repo2 +ostree_repo_init repo2 --mode=archive +${CMD_PREFIX} ostree --repo=repo2 pull-local repo +rm -rf test2-checkout +${CMD_PREFIX} ostree --repo=repo2 checkout -U --disable-cache test2 test2-checkout +if test -d repo2/uncompressed-objects-cache; then + ls repo2/uncompressed-objects-cache > ls.txt + if test -s ls.txt; then + assert_not_reached "repo has uncompressed objects" + fi +fi +rm test2-checkout -rf +${CMD_PREFIX} ostree --repo=repo2 checkout -U test2 test2-checkout +assert_file_has_content test2-checkout/baz/cow moo +assert_has_dir repo2/uncompressed-objects-cache +ls repo2/uncompressed-objects-cache > ls.txt +if ! test -s ls.txt; then + assert_not_reached "repo didn't cache uncompressed objects" +fi +# we're in archive mode, but the repo we pull-local from might be +# bare-user-only, in which case, we skip these checks since bare-user-only +# doesn't store permission bits +if ! is_bare_user_only_repo repo; then + assert_file_has_mode test2-checkout/baz/cowro 600 + assert_file_has_mode test2-checkout/baz/deeper/ohyeahx 755 +fi +echo "ok disable cache checkout" + +cd ${test_tmpdir} +rm checkout-test2 -rf +$OSTREE checkout test2 checkout-test2 +date > checkout-test2/date.txt +rm repo/tmp/* -rf +export TEST_BOOTID=3072029c-8b10-60d1-d31b-8422eeff9b42 +if env OSTREE_REPO_TEST_ERROR=pre-commit OSTREE_BOOTID=${TEST_BOOTID} \ + $OSTREE commit ${COMMIT_ARGS} -b test2 -s '' $test_tmpdir/checkout-test2 2>err.txt; then + assert_not_reached "Should have hit OSTREE_REPO_TEST_ERROR_PRE_COMMIT" +fi +assert_file_has_content err.txt OSTREE_REPO_TEST_ERROR_PRE_COMMIT +found_staging=0 +for d in $(find repo/tmp/ -maxdepth 1 -type d); do + bn=$(basename $d) + if test ${bn##staging-} != ${bn}; then + assert_str_match "${bn}" "^staging-${TEST_BOOTID}-" + found_staging=1 + fi +done +assert_streq "${found_staging}" 1 +echo "ok test error pre commit/bootid" + +# Whiteouts +cd ${test_tmpdir} +mkdir -p overlay/baz/ +if touch overlay/baz/.wh.cow && touch overlay/.wh.deeper && touch overlay/baz/another/.wh..wh..opq; then + touch overlay/anewfile + mkdir overlay/anewdir/ + touch overlay/anewdir/blah + $OSTREE --repo=repo commit ${COMMIT_ARGS} -b overlay -s 'overlay' --tree=dir=overlay + rm overlay -rf + + for branch in test2 overlay; do + $OSTREE --repo=repo checkout --union --whiteouts ${branch} overlay-co + done + for f in .wh.deeper baz/cow baz/.wh.cow; do + assert_not_has_file overlay-co/${f} + done + assert_not_has_dir overlay-co/deeper + assert_has_file overlay-co/anewdir/blah + assert_has_file overlay-co/anewfile + assert_not_has_file overlay-co/baz/another/y + + # And test replacing a directory wholesale with a symlink as well as a regular file + mkdir overlay + echo baz to file > overlay/baz + ln -s anewfile overlay/anewdir + $OSTREE --repo=repo commit ${COMMIT_ARGS} -b overlay-dir-convert --tree=dir=overlay + rm overlay -rf + + rm overlay-co -rf + for branch in test2 overlay-dir-convert; do + $OSTREE --repo=repo checkout --union --whiteouts ${branch} overlay-co + done + assert_has_file overlay-co/baz + test -L overlay-co/anewdir + + echo "ok whiteouts enabled" + + # Now double check whiteouts are not processed without --whiteouts + rm overlay-co -rf + for branch in test2 overlay; do + $OSTREE --repo=repo checkout --union ${branch} overlay-co + done + for f in .wh.deeper baz/cow baz/.wh.cow; do + assert_has_file overlay-co/${f} + done + assert_not_has_dir overlay-co/deeper + assert_has_file overlay-co/anewdir/blah + assert_has_file overlay-co/anewfile + echo "ok whiteouts disabled" +else + echo "ok # SKIP whiteouts do not work, are you using aufs?" + echo "ok # SKIP whiteouts do not work, are you using aufs?" +fi + +cd ${test_tmpdir} +rm -rf test2-checkout +mkdir -p test2-checkout +cd test2-checkout +echo 'should not be fsynced' > should-not-be-fsynced +if ! skip_one_without_strace_fault_injection; then + # Test that --fsync=false doesn't fsync + fsync_inject_error_ostree="strace -o /dev/null -f -e inject=syncfs,fsync,sync:error=EPERM ostree" + ${fsync_inject_error_ostree} --repo=${test_tmpdir}/repo commit ${COMMIT_ARGS} -b test2-no-fsync --fsync=false + # And test that we get EPERM if we inject an error + if ${fsync_inject_error_ostree} --repo=${test_tmpdir}/repo commit ${COMMIT_ARGS} -b test2-no-fsync 2>err.txt; then + fatal "fsync error injection failed" + fi + assert_file_has_content err.txt 'sync.*Operation not permitted' + echo "ok fsync disabled" +fi + +# Run this test only as non-root user. When run as root, the chmod +# won't have any effect. +if test "$(id -u)" != "0"; then + cd ${test_tmpdir} + rm -f expected-fail error-message + $OSTREE init --mode=archive --repo=repo-noperm + chmod -w repo-noperm/objects + $OSTREE --repo=repo-noperm pull-local repo 2> error-message || touch expected-fail + chmod +w repo-noperm/objects + assert_has_file expected-fail + assert_file_has_content error-message "Permission denied" + echo "ok unwritable repo was caught" +else + echo "ok # SKIP not run when root" +fi diff --git a/tests/bootloader-entries-crosscheck.py b/tests/bootloader-entries-crosscheck.py new file mode 100755 index 0000000..41f6956 --- /dev/null +++ b/tests/bootloader-entries-crosscheck.py @@ -0,0 +1,112 @@ +#!/usr/bin/python3 +# +# Copyright (C) 2015 Red Hat +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +import os +import sys + +if len(sys.argv) == 1: + sysroot = '' +else: + sysroot = sys.argv[1] + +bootloader = sys.argv[2] +loaderpath = sysroot + '/boot/loader/entries' +syslinuxpath = sysroot + '/boot/syslinux/syslinux.cfg' + +if bootloader == "grub2": + sys.stdout.write('GRUB2 configuration validation not implemented.\n') + sys.exit(0) + +def fatal(msg): + sys.stderr.write(msg) + sys.stderr.write('\n') + sys.exit(1) + +def entry_get_version(entry): + return int(entry['version']) + +def get_ostree_option(optionstring): + for o in optionstring.split(): + if o.startswith('ostree='): + return o[8:] + raise ValueError('ostree= not found') + +entries = [] +syslinux_entries = [] + +# Parse loader configs +for fname in os.listdir(loaderpath): + path = os.path.join(loaderpath, fname) + with open(path) as f: + entry = {} + for line in f: + line = line.strip() + if (line == '' or line.startswith('#')): + continue + s = line.find(' ') + assert s > 0 + k = line[0:s] + v = line[s+1:] + entry[k] = v + entries.append(entry) + entries.sort(key=entry_get_version, reverse=True) + +# Parse SYSLINUX config +with open(syslinuxpath) as f: + in_ostree_config = False + syslinux_entry = None + syslinux_default = None + for line in f: + line = line.strip() + if line.startswith('DEFAULT '): + if syslinux_entry is not None: + syslinux_default = line.split(' ', 1)[1] + elif line.startswith('LABEL '): + if syslinux_entry is not None: + syslinux_entries.append(syslinux_entry) + syslinux_entry = {} + syslinux_entry['title'] = line.split(' ', 1)[1] + elif line.startswith('KERNEL '): + syslinux_entry['linux'] = line.split(' ', 1)[1] + elif line.startswith('INITRD '): + syslinux_entry['initrd'] = line.split(' ', 1)[1] + elif line.startswith('APPEND '): + syslinux_entry['options'] = line.split(' ', 1)[1] + if syslinux_entry is not None: + syslinux_entries.append(syslinux_entry) + +if len(entries) != len(syslinux_entries): + fatal("Found {0} loader entries, but {1} SYSLINUX entries\n".format(len(entries), len(syslinux_entries))) + +def assert_matches_key(a, b, key): + aval = a[key] + bval = b[key] + if aval != bval: + fatal("Mismatch on {0}: {1} != {2}".format(key, aval, bval)) + +for i,(entry,syslinuxentry) in enumerate(zip(entries, syslinux_entries)): + assert_matches_key(entry, syslinuxentry, 'linux') + assert_matches_key(entry, syslinuxentry, 'initrd') + entry_ostree = get_ostree_option(entry['options']) + syslinux_ostree = get_ostree_option(syslinuxentry['options']) + if entry_ostree != syslinux_ostree: + fatal("Mismatch on ostree option: {0} != {1}".format(entry_ostree, syslinux_ostree)) + +sys.stdout.write('SYSLINUX configuration validated\n') +sys.exit(0) diff --git a/tests/coccinelle.sh b/tests/coccinelle.sh new file mode 100755 index 0000000..eb22662 --- /dev/null +++ b/tests/coccinelle.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# Run the .cocci files in the tests directory; these act +# as a blacklist. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +if ! spatch --version 2>/dev/null; then + skip "no spatch; get it from http://coccinelle.lip6.fr/" +fi + +if test -z "${OSTREE_UNINSTALLED_SRCDIR:-}"; then + skip "running installed?" +fi + +coccitests=$(ls $(dirname $0)/coccinelle/*.cocci) +echo "1.."$(echo ${coccitests} | wc -l) + +for cocci in $(dirname $0)/coccinelle/*.cocci; do + echo "Running: ${cocci}" + spatch --very-quiet --dir ${OSTREE_UNINSTALLED_SRCDIR} ${cocci} > cocci.out + if test -s cocci.out; then + sed -e 's/^/# /' < cocci.out >&2 + fatal "Failed semantic patch: ${cocci}" + fi + echo ok ${cocci} +done diff --git a/tests/corrupt-repo-ref.js b/tests/corrupt-repo-ref.js new file mode 100755 index 0000000..3af8f67 --- /dev/null +++ b/tests/corrupt-repo-ref.js @@ -0,0 +1,98 @@ +#!/usr/bin/env gjs +// +// Copyright (C) 2014 Colin Walters +// +// SPDX-License-Identifier: LGPL-2.0+ +// +// 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 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., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; +const OSTree = imports.gi.OSTree; + +let repoPathArg = ARGV[0]; +let refToCorrupt = ARGV[1]; + +let repo = OSTree.Repo.new(Gio.File.new_for_path(repoPathArg)); + +repo.open(null); + +function listObjectChecksumsRecurse(dir, allObjects) { + dir.ensure_resolved(); + allObjects[dir.tree_get_contents_checksum() + '.dirtree'] = true; + allObjects[dir.get_checksum() + '.dirmeta'] = true; + let e = dir.enumerate_children('standard::name,standard::type', 0, null); + let info; + while ((info = e.next_file(null)) != null) { + let child = e.get_child(info); + child.ensure_resolved(); + print(info.get_name() + " is " + info.get_file_type()); + if (info.get_file_type() == Gio.FileType.DIRECTORY) { + listObjectChecksumsRecurse(child, allObjects); + } else { + allObjects[child.get_checksum() + '.filez'] = true; + } + } + e.close(null); +} + +let [,root,commit] = repo.read_commit(refToCorrupt, null); +let allObjects = {}; +allObjects[commit + '.commit'] = true; +listObjectChecksumsRecurse(root, allObjects); +let i = 0; +for (let v in allObjects) + i++; +print("commit " + commit + " refers to " + i + " objects"); +let offset = GLib.random_int_range(0, i); +let objectToCorrupt = null; +for (let v in allObjects) { + if (offset <= 0) { + objectToCorrupt = v; + break; + } + offset--; +} +print("Choosing " + objectToCorrupt + " to corrupt"); + +let loosePath = repo.get_path().resolve_relative_path('objects/' + objectToCorrupt.substring(0, 2) + "/" + objectToCorrupt.substring(2)); + +let iostream = loosePath.open_readwrite(null); +let info = iostream.query_info('standard::size', null); +let size = info.get_size(); +let datain = Gio.DataInputStream.new(iostream.get_input_stream()); +let dataout = Gio.DataOutputStream.new(iostream.get_output_stream()); +let bytesToChange = 10; +let status = ""; +var bytesChanged = {} +for (i = 0; i < bytesToChange; i++) { + let byteOffsetToCorrupt; + do { + byteOffsetToCorrupt = GLib.random_int_range(0, size); + } while (byteOffsetToCorrupt in bytesChanged); + iostream.seek(byteOffsetToCorrupt, GLib.SeekType.SET, null); + let inbyte = datain.read_byte(null); + let outbyte = (inbyte + 1) % 255; + dataout.put_byte(outbyte, null); + bytesChanged[byteOffsetToCorrupt] = byteOffsetToCorrupt; + status += "Changed byte offset " + byteOffsetToCorrupt + " from " + inbyte + " to " + outbyte + "\n"; +} +dataout.flush(null); +iostream.close(null); + +print(status); +let successFile = Gio.File.new_for_path('corrupted-status.txt'); +successFile.replace_contents(status, null, false, 0, null); diff --git a/tests/fah-deltadata-new.tar.xz b/tests/fah-deltadata-new.tar.xz new file mode 100644 index 0000000..aea6a02 Binary files /dev/null and b/tests/fah-deltadata-new.tar.xz differ diff --git a/tests/fah-deltadata-old.tar.xz b/tests/fah-deltadata-old.tar.xz new file mode 100644 index 0000000..8768733 Binary files /dev/null and b/tests/fah-deltadata-old.tar.xz differ diff --git a/tests/get-byte-order.c b/tests/get-byte-order.c new file mode 100644 index 0000000..7e7ba31 --- /dev/null +++ b/tests/get-byte-order.c @@ -0,0 +1,12 @@ +/* Helper for OSTree tests: return host byte order */ + +#include "config.h" + +#include + +int +main (void) +{ + g_print ("%d\n", G_BYTE_ORDER); + return 0; +} diff --git a/tests/glib.supp b/tests/glib.supp new file mode 100644 index 0000000..7ac6ed8 --- /dev/null +++ b/tests/glib.supp @@ -0,0 +1,562 @@ +# This GLib suppressions file is known to be used at least by: +# +# - rpm-software-management/libhif +# +# Please use the upstream verison in libhif for changes. +{ + gobject_init_1 + Memcheck:Leak + ... + fun:gobject_init +} +{ + g_type_register_static_1 + Memcheck:Leak + ... + fun:g_type_register_static +} +{ + g_type_register_dynamic + Memcheck:Leak + ... + fun:g_type_register_dynamic +} +{ + g_type_register_fundamental + Memcheck:Leak + ... + fun:g_type_register_fundamental +} +{ + g_type_init_with_debug_flags + Memcheck:Leak + ... + fun:g_type_init_with_debug_flags +} +{ + g_type_class_ref_1 + Memcheck:Leak + ... + fun:type_iface_vtable_base_init_Wm + ... + fun:g_type_class_ref +} +{ + g_type_class_ref_2 + Memcheck:Leak + ... + fun:type_class_init_Wm + ... + fun:g_type_class_ref +} +{ + g_type_add_interface_static + Memcheck:Leak + ... + fun:g_type_add_interface_static +} +{ + g_type_add_interface_dynamic + Memcheck:Leak + ... + fun:g_type_add_interface_dynamic +} +{ + g_param_spec_internal + Memcheck:Leak + ... + fun:g_type_class_ref + fun:g_type_create_instance + fun:g_param_spec_internal +} +{ + g_param_spec_enum + Memcheck:Leak + ... + fun:g_type_class_ref + fun:g_param_spec_enum +} +{ + g_param_spec_flags + Memcheck:Leak + ... + fun:g_type_class_ref + fun:g_param_spec_flags +} +{ + g_quark_from_static_string + Memcheck:Leak + ... + fun:g_quark_from_static_string +} +{ + g_quark_from_string + Memcheck:Leak + ... + fun:g_quark_from_string +} +{ + g_value_register_transform_func + Memcheck:Leak + ... + fun:g_value_register_transform_func +} +{ + test_run_seed + Memcheck:Leak + ... + fun:g_rand_new_with_seed_array + fun:test_run_seed + ... + fun:g_test_run_suite +} +{ + g_test_init + Memcheck:Leak + ... + fun:g_rand_new_with_seed_array + ... + fun:g_test_init +} +{ + g_intern_static_string + Memcheck:Leak + ... + fun:g_intern_static_string +} +{ + g_main_context_push_thread_default + Memcheck:Leak + ... + fun:g_queue_new + fun:g_main_context_push_thread_default +} +{ + g_main_context_push_thread_default_inlined + Memcheck:Leak + ... + fun:g_slice_alloc0 + fun:g_main_context_push_thread_default +} +{ + g_dbus_error_register_error + Memcheck:Leak + ... + fun:g_dbus_error_register_error +} +{ + g_param_spec_pool_insert + Memcheck:Leak + ... + fun:g_param_spec_pool_insert +} +{ + g_main_context_default + Memcheck:Leak + ... + fun:g_main_context_default +} +{ + g_main_context_check + Memcheck:Leak + ... + fun:g_ptr_array_add + fun:g_main_context_check +} +{ + g_test_run_suite + Memcheck:Leak + ... + fun:g_slist_copy + fun:g_test_run_suite_internal + fun:g_test_run_suite +} +{ + g_dbus_interface_info_cache_build + Memcheck:Leak + ... + fun:g_dbus_interface_info_cache_build +} +{ + g_cancellable_push_current + Memcheck:Leak + ... + fun:thread_memory_from_self + ... + fun:g_cancellable_push_current +} +{ + _g_io_module_get_default + Memcheck:Leak + ... + fun:g_io_module_new + fun:g_io_modules_scan_all_in_directory_with_scope + fun:_g_io_modules_ensure_loaded + fun:_g_io_module_get_default +} +{ + g_io_scheduler_push_job + Memcheck:Leak + ... + fun:init_scheduler + fun:g_once_impl + fun:g_io_scheduler_push_job +} +{ + g_io_scheduler_push_job_2 + Memcheck:Leak + ... + fun:g_system_thread_new + ... + fun:g_io_scheduler_push_job +} +{ + g_bus_get_sync__available_connections + Memcheck:Leak + ... + fun:g_hash_table_new + fun:initable_init + fun:g_initable_init + fun:g_bus_get_sync +} +{ + g_socket_connection_factory_register_type + Memcheck:Leak + ... + fun:g_socket_connection_factory_register_type +} +{ + g_test_add_vtable + Memcheck:Leak + ... + fun:g_test_add_vtable +} +{ + g_mutex_lock + Memcheck:Leak + ... + fun:g_mutex_impl_new + fun:g_mutex_get_impl + fun:g_mutex_lock +} +{ + g_thread_self + Memcheck:Leak + ... + fun:g_thread_self +} +{ + g_rec_mutex_lock + Memcheck:Leak + ... + fun:g_rec_mutex_impl_new + fun:g_rec_mutex_get_impl + fun:g_rec_mutex_lock +} +{ + test_case_run + Memcheck:Leak + ... + fun:g_malloc0 + fun:test_case_run + ... + fun:g_test_run_suite +} +{ + g_get_charset + Memcheck:Leak + ... + fun:g_get_charset +} +{ + g_test_run_suite__timer_new + Memcheck:Leak + ... + fun:g_timer_new + fun:test_case_run + ... + fun:g_test_run_suite +} +{ + g_test_run_suite__timer_new2 + Memcheck:Leak + ... + fun:g_timer_new + fun:test_case_run_suite_internal + ... + fun:g_test_run_suite +} +{ + g_test_run_suite__strconcat + Memcheck:Leak + ... + fun:g_strconcat + fun:test_case_run + ... + fun:g_test_run_suite + fun:g_test_run +} +{ + g_type_interface_add_prerequisite + Memcheck:Leak + ... + fun:g_type_interface_add_prerequisite +} +{ + + Memcheck:Leak + ... + fun:g_slist_copy + fun:g_test_run_suite_internal + ... + fun:g_test_run_suite +} +{ + g_set_prgname + Memcheck:Leak + ... + fun:g_set_prgname +} +{ + g_test_run_suite__strconcat_2 + Memcheck:Leak + ... + fun:g_strconcat + fun:g_test_run_suite_internal +} +{ + g_test_run_suite__strdup + Memcheck:Leak + ... + fun:g_strdup + fun:g_test_run_suite_internal +} +{ + g_private_get + Memcheck:Leak + ... + fun:g_private_get +} +{ + g_private_set + Memcheck:Leak + ... + fun:g_private_set +} +{ + g_static_mutex_get_mutex_impl + Memcheck:Leak + ... + fun:g_static_mutex_get_mutex_impl +} +{ + g_variant_type_info_unref + Memcheck:Leak + ... + fun:g_hash_table_remove + fun:g_variant_type_info_unref +} +{ + g_rw_lock_reader_lock + Memcheck:Leak + ... + fun:g_rw_lock_impl_new + fun:g_rw_lock_get_impl + fun:g_rw_lock_reader_lock +} +{ + g_child_watch_finalize__rt_sigaction + Memcheck:Param + rt_sigaction(act->sa_flags) + fun:__libc_sigaction + ... + fun:g_child_watch_finalize +} +{ + g_dbus_worker_new + Memcheck:Leak + fun:calloc + ... + fun:_g_dbus_worker_new +} +{ + gdbus_shared_thread_func + Memcheck:Leak + match-leak-kinds: definite + ... + fun:g_malloc + ... + fun:gdbus_shared_thread_func +} +{ + g_task_start_task_thread + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:g_malloc + fun:g_slice_alloc + fun:g_slice_alloc0 + ... + fun:g_thread_pool_push + fun:g_task_start_task_thread +} +{ + g_task_to_pool + Memcheck:Leak + ... + fun:g_thread_pool_start_thread + ... + fun:g_task_run_in_thread +} +{ + g_get_language_names + Memcheck:Leak + match-leak-kinds: definite + fun:calloc + fun:g_malloc0 + fun:g_get_language_names +} +{ + g_get_filename_charsets + Memcheck:Leak + match-leak-kinds: definite + ... + fun:g_get_filename_charsets + fun:g_filename_display_name +} +{ + g_main_current_source + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:g_malloc + ... + fun:g_main_current_source + fun:g_task_return + fun:g_task_thread_pool_thread +} +{ + g_once_init_enter + Memcheck:Leak + match-leak-kinds: definite + ... + fun:g_once_init_enter +} +{ + g_child_watch_source_new + Memcheck:Leak + match-leak-kinds: definite + ... + fun:g_thread_new + ... + fun:g_child_watch_source_new +} +{ + continue_writing_in_idle_cb + Memcheck:Leak + match-leak-kinds: definite + ... + fun:g_task_new + ... + fun:continue_writing_in_idle_cb + fun:g_main_context_dispatch +} +{ + g_main_current_source + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + ... + fun:g_main_current_source +} +{ + g_thread_pool_push + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + ... + fun:g_thread_pool_push +} +{ + leak_test_dbus_dispose + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + ... + fun:g_main_loop_run + fun:g_test_dbus_down +} +{ + leak_test_dbus_down + Memcheck:Leak + match-leak-kinds: definite + fun:calloc + fun:g_malloc0 + fun:g_main_loop_new + fun:g_test_dbus_down +} +{ + leak_socket_client_connect + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:g_malloc + fun:g_slice_alloc + fun:g_slice_alloc0 + fun:g_socket_client_connect_async + fun:g_socket_client_connect_to_uri_async +} +{ + leak_signal_handlers_disconnect_matched + Memcheck:Leak + match-leak-kinds: definite + fun:calloc + fun:g_malloc0 + ... + fun:g_slice_alloc + ... + fun:g_signal_handlers_disconnect_matched +} +{ + g_tls_connection_gnutls_init_priorities + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:g_malloc + fun:g_strdup + fun:g_tls_connection_gnutls_init_priorities +} +{ + g_tls_connection_gnutls_heisenbug_likely_same_as_above + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:g_malloc + fun:g_strdup + ... + fun:g_tls_client_connection_new +} +{ + g_unix_signal_add_full + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:g_malloc + ... + fun:g_thread_new + ... + fun:g_unix_signal_add_full +} +{ + glib_worker_1 + Memcheck:Leak + ... + fun:glib_worker_main +} +{ + glib_worker_2 + Memcheck:Leak + ... + fun:g_thread_new + fun:g_get_worker_context +} diff --git a/tests/gpg-verify-data/README.md b/tests/gpg-verify-data/README.md new file mode 100644 index 0000000..9ca4758 --- /dev/null +++ b/tests/gpg-verify-data/README.md @@ -0,0 +1,7 @@ +This is a GPG config directory for use with the OstreeGpgVerifyResult +test cases. The test data (`lgpl2`) is signed with a variety of valid +and invalid GPG keys in a detached signature file (`lgpl2.sig`). In +addition, each detached signature is available in a separate file +(`lgpgl2.sig`). + +The passphrase for all the keys is `redhat`. diff --git a/tests/gpg-verify-data/gpg.conf b/tests/gpg-verify-data/gpg.conf new file mode 100644 index 0000000..55cd4bb --- /dev/null +++ b/tests/gpg-verify-data/gpg.conf @@ -0,0 +1,4 @@ +# This prevents GPG from attempting to create lock files when accessing +# the keyrings and trust database. Necessary for "distcheck", since the +# GPG homedir will be read-only. +lock-never diff --git a/tests/gpg-verify-data/lgpl2 b/tests/gpg-verify-data/lgpl2 new file mode 100644 index 0000000..5bc8fb2 --- /dev/null +++ b/tests/gpg-verify-data/lgpl2 @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 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 library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + 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 Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the 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 a program 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. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + 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, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile 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) 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. + + c) 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. + + d) 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 source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + 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 to +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 Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/tests/gpg-verify-data/lgpl2.sig b/tests/gpg-verify-data/lgpl2.sig new file mode 100644 index 0000000..4229b81 Binary files /dev/null and b/tests/gpg-verify-data/lgpl2.sig differ diff --git a/tests/gpg-verify-data/lgpl2.sig0 b/tests/gpg-verify-data/lgpl2.sig0 new file mode 100644 index 0000000..375c650 Binary files /dev/null and b/tests/gpg-verify-data/lgpl2.sig0 differ diff --git a/tests/gpg-verify-data/lgpl2.sig1 b/tests/gpg-verify-data/lgpl2.sig1 new file mode 100644 index 0000000..83a6227 Binary files /dev/null and b/tests/gpg-verify-data/lgpl2.sig1 differ diff --git a/tests/gpg-verify-data/lgpl2.sig2 b/tests/gpg-verify-data/lgpl2.sig2 new file mode 100644 index 0000000..ad0f420 Binary files /dev/null and b/tests/gpg-verify-data/lgpl2.sig2 differ diff --git a/tests/gpg-verify-data/lgpl2.sig3 b/tests/gpg-verify-data/lgpl2.sig3 new file mode 100644 index 0000000..5c17ec6 Binary files /dev/null and b/tests/gpg-verify-data/lgpl2.sig3 differ diff --git a/tests/gpg-verify-data/lgpl2.sig4 b/tests/gpg-verify-data/lgpl2.sig4 new file mode 100644 index 0000000..2d3989f Binary files /dev/null and b/tests/gpg-verify-data/lgpl2.sig4 differ diff --git a/tests/gpg-verify-data/pubring.gpg b/tests/gpg-verify-data/pubring.gpg new file mode 100644 index 0000000..2c9e5b6 Binary files /dev/null and b/tests/gpg-verify-data/pubring.gpg differ diff --git a/tests/gpg-verify-data/secring.gpg b/tests/gpg-verify-data/secring.gpg new file mode 100644 index 0000000..38e7f1c Binary files /dev/null and b/tests/gpg-verify-data/secring.gpg differ diff --git a/tests/gpg-verify-data/trustdb.gpg b/tests/gpg-verify-data/trustdb.gpg new file mode 100644 index 0000000..91f8717 Binary files /dev/null and b/tests/gpg-verify-data/trustdb.gpg differ diff --git a/tests/gpghome/key1.asc b/tests/gpghome/key1.asc new file mode 100644 index 0000000..17113b5 --- /dev/null +++ b/tests/gpghome/key1.asc @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFIuhBYBCADTbnocQsJgMfOELkFt3wRrAZShijoBPYZT9BrIuIKZxAbaxZJr +Tbw8eIGgHZ51NCfdoikul0i82dt4hwtsACNVL5EGRmvTIKHPacb0yJMr1YBjcSwD +Slo+niLPb/oVtLTbDWFt/msYKREF/lGJT9dJyXkQ5UOwWdipDaHIlwb0IKUvL7cu +NpNthRFRm1M5d5M9OtqTCrCja6zckQ6OfvoStsbneHzfVWeH7vLcKBxxkfDhusVt +y1iVaDk1EYT8ZxsrAWw4S7nRK/bjr86IYpFPjG2aKMd9qxyIo7hcX4r8od24jzfM +v/ysOapnkTJuv8J6v7MakM1HkCz+TKF6gXxVABEBAAG0HU9zdHJlZSBUZXN0ZXIg +PHRlc3RAdGVzdC5jb20+iQE5BBMBAgAjBQJSLoQWAhsDBwsJCAcDAgEGFQgCCQoL +BBYCAwECHgECF4AACgkQf8oj2Ecs2vr/9wgAnme6WsWQy8CYeGH4q/5I6XFL6q1m +S0+qdeGnYRmR0jJAGJ84vqDhnKxjeQzp+8Nq81DHGEJBszCkMW2o22neFi2Mo95h +Dq3GWNZVldCDshjPs563AY6j7zACUN7Cy5XB3MK/vj5R/SrHBtJmSgPTx9WfmUgn +n5Udg+fzSsS8z8DUtJFtexgrSnEmwH+nOmIfrsjIYL5EPg+CTTalhygROrERjINr +pCYiShaFCKbuyt/XvyQ71y0JbB2yS7tDv0mL4SZjSuBQ1PkNE8ZQsymqBOJHA1Y3 +ppgPs1OenmtYgxaR8HQQv7uxHWZz0dmwQN93Qx8zMZwW40Odmdh1zLNQf7kBDQRS +LoQWAQgA9i9QWg28qmFrPIzn90ZlNlUtFzoZy/8/lIk34awge1uO5aHydYBzkuWU +jCDyBtQLWZQlwOKq8oHBbjENR2sfsmNkrYKcceQ02hSXqEJkc6jcDMCpB9eWy34K +sPZmdl76Eo/vIIgRqJ9JPeGoMPaIBg2ouEz6Ft6jcX3EriYIKebCEA9wPk29z40x +7D8mBZn06WrZ3JyePfbCdNJlQANEnrk7KDMNwPhhE1wcfPkiVtqBR0/FwIoUP0jn +PishIWOuFObYnXQQ2R8sxrw/V0hGqVTh+k+iNAjzEp4yPsAvB+LdMH9nCY5rU3Vo +1paEqVM1EHoBPu4NupRN0AjIJPr5UQARAQABiQEfBBgBAgAJBQJSLoQWAhsMAAoJ +EH/KI9hHLNr68i4IAMdc+EgAaPZFWZcXFGBfhnOKQFC/u/W6Cu1JjqIYkGO0HxSh +SfBkxArqlp37w4YVH4bUku6ja421bfGFNMtMfXjw2mU3HRdaDenP6OGv2jYmYmFt +6zi0JZZhvi8ZCcAQTStZ2Ms3hwstCMiBXPmYA7KW9Gzo4JQSKCW5haICGVSWl7kh +n0OkhOTVI9uzNr7+LhYn2ib/ynSaMKeI4hZ8v1HDuY0V1E63vFPGLFBTPaoRPpnm +9yBnXMWhrbV97L6eEoe7faurSyPcF11LEFC5x8oENnbH+wtAXOayQo3lld+JRa9C +JEZl8STdRU9o2NFwF8XM8BEOWntMS8aNpPoILC8= +=ZNNc +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/gpghome/key2.asc b/tests/gpghome/key2.asc new file mode 100644 index 0000000..3338329 --- /dev/null +++ b/tests/gpghome/key2.asc @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFUIM4ABCADYBuvzGgzv5nMy2wICv79l+N4bN9/o9hTdFEOzyAeCEaF5Wugc +L9nfTgUS9NRHsSpGt9DeZVEzRm5XzccgHOPs7MlYH0Irhc4Hb9ycOO2vBZ7ZiBK/ +jbY+R5GN4Ut9XIRexbXWddOjJpRUTCWQeXw5iqV9Puqm1ge2Vcal+NZOi2AFRKKe +p/QI9EXIIx7ca6OWtH2SS/qE2p9obDYsMNrW+Dk623dbNKQiWaWyfRD+hB91UNbt +vK7agokTeU0hKr9C8dHrhepgl9B/Hz8SFibZQQiTxSiVH3fUu10eQsyuDC/01KHp +z0MR28Lc4VlCs6dsJBmGMBayHHVzbyXgw6uZABEBAAG0IU9zdHJlZSBUZXN0ZXIg +SUkgPHRlc3QyQHRlc3QuY29tPokBOAQTAQIAIgUCVQgzgAIbAwYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AACgkQ2CKM/sqVDUFpJAgAirtYbbkvnlKtBxDsCu+A6qyl +7r+cW8IH5U1P4MqxqQwkAe1ZalfjuTSHVKYqt/K6gt0+4NvCee3A2JxXTvLq1hdR +DNMUFAjkbZv3Y6VS8Qtj3edsviNEB7s8uyWgR/EBB312YSZCwzk5uSLzM5E7AmvM +0/ZPIAAxjz8TpQKc8vJx1/4nqgt0Wjv5B74vuOQJT26zoFygCQM76YeN+ULzk/hN +hW7aNp/S2STasvEv7NgwqAe6eWy45xTrvxhEhQV760/toLbI0DuuBGr6Ue/G+Id4 +P/R604HAbMg3GdCztyoD3WTuvcsY6oXD7GlSEX4DZ0LA2TqQDZB+Pqe2yF7Gi7kB +DQRVCDOAAQgAsxH2E9JeQPbcdXGyxLCa4FyMeziCrxn7tOEsRkeqZmb76mAOn67Q +ZuZ6SXcAQDjKOBu7QNEcFQ+bAW/urohzD/sjr09vKqibLh6v8t81DE79GHI1UZ7F +SuYDLgcGUvOCJej8iftJcudWuzCW9SvoykNcgPcIOYEXbbJVRr2xvK4z2a34DyWL +jEXU2r6g1KNwtGyT6hZ7Ax99MKAzCFX3to0V51EXcrnUojwz/8i4Lal9t3d4P3lu +FZw3ITWh4e9zNxp8aSxsAN/vQ1EHccMPrNmO+d+yjhH7inTxf+vLErP3Cs5rPjxl +FgoLvBCSCT0jQ0xP+8Aa2TDyXDcMHg85QwARAQABiQEfBBgBAgAJBQJVCDOAAhsM +AAoJENgijP7KlQ1Bc68H/RBn5PpUe8CA1CJ8eN4LIfRee3DjacwvjGsdgiMzcLhb +Hp/ke42kentYjT+gF1ABPbeUERDlhnZ8BguKGZV+jOGDWRI2KFrQXL444aNznjn8 +aTOQY/d4LibwSaQ3qzf4Zp4CyZq2X2Vg3+B3HoUM6pkIL/r2ao5TnFqKubCE3sEo +St+LV4eHktoAS1GXmxYKo4Q67yMVekTZt7C/VQ2a20qfAXBn2U8UA3tUvNqKtyyJ +XrxeTJ+T4MMv60zdC/B/UPNjjHLNyB6culIzyiYFglGw3ctx2erJN2d+aQLrw78E +vIuMy+JcH6y3JlzVGdByWbC7628OcWWa+NL/CXnYMyQ= +=j9RC +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/gpghome/key3.asc b/tests/gpghome/key3.asc new file mode 100644 index 0000000..2ebdb6d --- /dev/null +++ b/tests/gpghome/key3.asc @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFUIM6EBCACr57QUYEEuxvkX20yM1LVt2jyYZRKKQsqXx/xCF+Pg1MNz6mYx +Qz6R6+yZZmlADsfRdnEpRvl4Dq2g3cP0DqkjnIKwI7ffEsyXlves8OMlpwT2Vh4x +8Lx92eIEeqmb+PT8m88+x+EPVaR2R5KBHFkGXGyVgw+Ry8Oa9ZtJEKSkL/EQvzWv +5q+OR1Pm8rnIPe64XPh3yAx5SBJ2m7hykH/XMVrdGqaZvpuGBx77pmmqfMMjNWMC +U09hURyuyGWUsj9lFWYgpBvAzASmJNpAf7FZTjzCwLJwqpxCYm6a3sp76yyjuY7q +vgJOolRHp9F/XETsSLdy6966oBxclGNaD6gnABEBAAG0Ik9zdHJlZSBUZXN0ZXIg +SUlJIDx0ZXN0M0B0ZXN0LmNvbT6JATgEEwECACIFAlUIM6ECGwMGCwkIBwMCBhUI +AgkKCwQWAgMBAh4BAheAAAoJEA0V+uffRE1n0n4H/0Z8bC1cdr5cMFZ6YBaJlw4c +b61krhan2qCrwQupwaXi6LHt0zMwgljOcN+X2sAlZj9Jv0CabU5S1vM1fh9DZ6OY +2OQ/Pq2lXGk22JjrbPPq5o//xTzo92Uxptuxq6O4frVzuGCo1yPlrHJh+TxbXIc8 +XOz9C9KTfcb9OwidSSW5LlUBzQ2e3oQLSUQPsdB3TZP5zlqPIYerWn+LdETKcOTr +JyoaobFqX2BN223d3vkA1/GcuB17eBnzbnS0OWLJH+E3bsCqjtCJMEc1uTq97tyF +XStIk9i0gVbA+GiK/ZFMt+a5kagR5dOUwpNZ0BE+Kzf0CtkSaSWkAh1vQV/j2E65 +AQ0EVQgzoQEIAMeXa6sp5kdmJn/fVw0Pk5oluBXif7BiFt+T7K03RxCOKRpne6dI +SS98ruwZ1B5hn0lZO0UiL5RKpBQUrI9Y7251tz+oWohU2ZkUwwP3OcBlTXtErhe0 +LctcJ1nUA5NICVP5brhJR94durULiM+Rrhr12Ccs+a9bV268btNLN51z7ICMwNI6 +xuNxLt9orVJwP82a2eelQOgkPyFpiq7UxZ1erJg4aBVfWHP+rlxyQlzawVebbQMO +gwYW+gAawTxd2x7PV9CC3KsaM+HI6wBvDOtcWlbzo+TxzcVocd5oern4Mr5Y86Gt +lajuO9DVsuxxIfBrvHdRut613ShhOVlfy2MAEQEAAYkBHwQYAQIACQUCVQgzoQIb +DAAKCRANFfrn30RNZyPVB/9jNFOjcNCAZSrz9vylaO0xHsPhIn4osmkiU6BvodwO +n+qR4eEUw7BzoWC5QqGxUPYuDneQK7N7U31SFYjmY5Y1CDMsFtcYzjPgN5qWhtaN +iNTtE9pb5f97PyLSUwcdW1y/cfDfqoAY6rpRXieo7hJv1xBtlEzJIbSSTS1SUEd1 +4qwPCqNWMSM6qBcaFB5Yuw0Z/E6B1JfNTUw5J5jDxbGdOzkLx2mXCldte1axq9Lp +1V17jMTvn7Ml1QdoEAqzvt4VNQci/Su/qd3XjQ46b4dFFP03+jJv7mO6tHka2luZ +RX0zfsk5q8wqbtV2k0XZFRD+22ddKMf1j4wID157lNQs +=Dq+d +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/gpghome/pubring.gpg b/tests/gpghome/pubring.gpg new file mode 100644 index 0000000..5461d9d Binary files /dev/null and b/tests/gpghome/pubring.gpg differ diff --git a/tests/gpghome/revocations/key1.rev b/tests/gpghome/revocations/key1.rev new file mode 100644 index 0000000..b918151 --- /dev/null +++ b/tests/gpghome/revocations/key1.rev @@ -0,0 +1,12 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: This is a revocation certificate + +iQE9BCABCgAnFiEEXmXedascUBhi1HY0f8oj2Ecs2voFAl0MvqgJHQBUZXN0aW5n +AAoJEH/KI9hHLNr6/dQH/iPZjfJgFAc/TIR4xE4kB0yL4zdMqxgV1ef/atQDLEN4 +MBiqIltzb8WyG+cpNfNZgFmqXmCRN+1IAla9piixe76ZwOqcQ6S5MU/8nMcyMsD9 +edg+9sg0DH8SEzejVma3ZLfaJ/6ZpU7c6a4vCPNcRBC7PxAvAc0LnAN6KQYGU7GR +gv2k/JsGYgvmUAajhVFy0jc4jGkhRBHMDksGGFdYY94RATFF4gWtlUXyRYMTXBCf +eM3bxEeSMbU7lXCZg9zjoxP6XzJuNW1SLz3zL90GnO19uNh8Pf6pHmkCNTO/L1Ua +Cc6fb3ubtdqgs6an84U/aod1VcK7BNASqZ2gYUsF2KE= +=owvo +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/gpghome/revocations/key2.rev b/tests/gpghome/revocations/key2.rev new file mode 100644 index 0000000..9b8960a --- /dev/null +++ b/tests/gpghome/revocations/key2.rev @@ -0,0 +1,12 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: This is a revocation certificate + +iQE9BCABCgAnFiEEezsQINdEeWh/2yJz2CKM/sqVDUEFAl0Mvs4JHQBUZXN0aW5n +AAoJENgijP7KlQ1BzH4IAMUoTrW6XraDYq/d/b0qa3sZ1NTBPUXLp4gFaedZwKk/ +AKSUCK05RWRQO3HrSvmhdSUF6/9tFLGpbu7P56ihjAnq2vpzRyeNTEGQ02IzfCpM +SJup0R6iA7KmjiDutDoEgjhAzxCKbnU71SQ3PmjyaQT1KCBCDJVptcY6HDbo0dRN +vcjTfjtFqkPgqbHyXwGv3rlm4uctSVfACrOS/fKF4Q9Fs4prsUXjQpGLaTHdxhiL +pMRCTfZ4DBEMwAY7s9FpMpIh9rdOwE+zkv5CsE0uJVZq0WW5r0CBDCta6Sopt6uk +pIA+QHL9GPOrG2E3SJxyIBC37Sl40MGAJQ1djmecIGk= +=0KEe +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/gpghome/revocations/key3.rev b/tests/gpghome/revocations/key3.rev new file mode 100644 index 0000000..66e238a --- /dev/null +++ b/tests/gpghome/revocations/key3.rev @@ -0,0 +1,12 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: This is a revocation certificate + +iQE9BCABCgAnFiEEfSnPBguCac32O/vdDRX6599ETWcFAl0MvuYJHQBUZXN0aW5n +AAoJEA0V+uffRE1n/p8H/3mmSK2gtbxJ5sfu1z44ra82fLRAUupJzf53dAvvJCEK +4RSJFtHYu+hoPVFd9bmToxo2YQWe67MMZW7cHtq9D/a755SYOrty//KpXsGS22W/ +ZGatBjl36zuE6BoR18Q6VAMgVBwovPSlSuCEW+Ro8JZYyA/LbA95AnMprNod6Jw9 +VSsGC39au5rUlhEOHLL1Iw3dl4blxa6tf/roljbXzaN+Qh2/ez7Cy532oocak2FL +bbblBGrIdfYLAXpLqhnQk2vgEHZ+ZylvStBndpLWwEskXhmaHpW7+WapFhLCUOr+ +arzbc9XQ7ghhF9hSoKiToJqU5PRjaOex85BEDwE5gWY= +=ykAF +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/gpghome/secring.gpg b/tests/gpghome/secring.gpg new file mode 100644 index 0000000..ad88437 Binary files /dev/null and b/tests/gpghome/secring.gpg differ diff --git a/tests/gpghome/trustdb.gpg b/tests/gpghome/trustdb.gpg new file mode 100644 index 0000000..d5f053e Binary files /dev/null and b/tests/gpghome/trustdb.gpg differ diff --git a/tests/gpghome/trusted/pubring.gpg b/tests/gpghome/trusted/pubring.gpg new file mode 100644 index 0000000..5461d9d Binary files /dev/null and b/tests/gpghome/trusted/pubring.gpg differ diff --git a/tests/libostreetest.c b/tests/libostreetest.c new file mode 100644 index 0000000..1efee40 --- /dev/null +++ b/tests/libostreetest.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include +#include + +#include "libglnx.h" +#include "libostreetest.h" + +/* This function hovers in a quantum superposition of horrifying and + * beautiful. Future generations may interpret it as modern art. + */ +gboolean +ot_test_run_libtest (const char *cmd, GError **error) +{ + const char *srcdir = g_getenv ("G_TEST_SRCDIR"); + g_autoptr(GPtrArray) argv = g_ptr_array_new (); + g_autoptr(GString) cmdstr = g_string_new (""); + + g_ptr_array_add (argv, "bash"); + g_ptr_array_add (argv, "-c"); + + g_string_append (cmdstr, "set -xeuo pipefail; . "); + g_string_append (cmdstr, srcdir); + g_string_append (cmdstr, "/tests/libtest.sh; "); + g_string_append (cmdstr, cmd); + + g_ptr_array_add (argv, cmdstr->str); + g_ptr_array_add (argv, NULL); + + int estatus; + if (!g_spawn_sync (NULL, (char**)argv->pdata, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, NULL, &estatus, error)) + return FALSE; + if (!g_spawn_check_exit_status (estatus, error)) + return FALSE; + + return TRUE; +} + +OstreeRepo * +ot_test_setup_repo (GCancellable *cancellable, + GError **error) +{ + if (!ot_test_run_libtest ("setup_test_repository archive", error)) + return NULL; + + g_autoptr(GFile) repo_path = g_file_new_for_path ("repo"); + g_autoptr(OstreeRepo) ret_repo = ostree_repo_new (repo_path); + if (!ostree_repo_open (ret_repo, cancellable, error)) + return NULL; + + return g_steal_pointer (&ret_repo); +} + +/* Determine whether we're able to relabel files. Needed for bare tests. */ +gboolean +ot_check_relabeling (gboolean *can_relabel, + GError **error) +{ + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, ".", O_RDWR | O_CLOEXEC, &tmpf, error)) + return FALSE; + + g_autoptr(GError) local_error = NULL; + g_autoptr(GBytes) bytes = glnx_fgetxattr_bytes (tmpf.fd, "security.selinux", &local_error); + if (!bytes) + { + /* libglnx preserves errno. The EOPNOTSUPP case can't be part of a + * 'case' statement because on most but not all architectures, + * it's numerically equal to ENOTSUP. */ + if (G_IN_SET (errno, ENOTSUP, ENODATA) || errno == EOPNOTSUPP) + { + *can_relabel = FALSE; + return TRUE; + } + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + gsize data_len; + const guint8 *data = g_bytes_get_data (bytes, &data_len); + if (fsetxattr (tmpf.fd, "security.selinux", data, data_len, 0) < 0) + { + if (errno == ENOTSUP || errno == EOPNOTSUPP) + { + *can_relabel = FALSE; + return TRUE; + } + return glnx_throw_errno_prefix (error, "fsetxattr"); + } + + *can_relabel = TRUE; + return TRUE; +} + +/* Determine whether the filesystem supports getting/setting user xattrs. */ +gboolean +ot_check_user_xattrs (gboolean *has_user_xattrs, + GError **error) +{ + g_auto(GLnxTmpfile) tmpf = { 0, }; + if (!glnx_open_tmpfile_linkable_at (AT_FDCWD, ".", O_RDWR | O_CLOEXEC, &tmpf, error)) + return FALSE; + + if (fsetxattr (tmpf.fd, "user.test", "novalue", strlen ("novalue"), 0) < 0) + { + if (errno == ENOTSUP || errno == EOPNOTSUPP) + { + *has_user_xattrs = FALSE; + return TRUE; + } + return glnx_throw_errno_prefix (error, "fsetxattr"); + } + + *has_user_xattrs = TRUE; + return TRUE; +} + +OstreeSysroot * +ot_test_setup_sysroot (GCancellable *cancellable, + GError **error) +{ + if (!ot_test_run_libtest ("setup_os_repository \"archive\" \"syslinux\"", error)) + return FALSE; + + g_autoptr(GString) buf = g_string_new ("mutable-deployments"); + + gboolean can_relabel = FALSE; + if (!ot_check_relabeling (&can_relabel, error)) + return FALSE; + if (!can_relabel) + { + g_print ("libostreetest: can't relabel, turning off xattrs\n"); + g_string_append (buf, ",no-xattrs"); + } + + /* Make sure deployments are mutable */ + g_setenv ("OSTREE_SYSROOT_DEBUG", buf->str, TRUE); + + g_autoptr(GFile) sysroot_path = g_file_new_for_path ("sysroot"); + return ostree_sysroot_new (sysroot_path); +} diff --git a/tests/libostreetest.h b/tests/libostreetest.h new file mode 100644 index 0000000..d1bd61f --- /dev/null +++ b/tests/libostreetest.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +gboolean ot_test_run_libtest (const char *cmd, GError **error); + +OstreeRepo *ot_test_setup_repo (GCancellable *cancellable, + GError **error); + +gboolean ot_check_relabeling (gboolean *can_relabel, + GError **error); + +gboolean ot_check_user_xattrs (gboolean *has_user_xattrs, + GError **error); + +OstreeSysroot *ot_test_setup_sysroot (GCancellable *cancellable, + GError **error); + +G_END_DECLS diff --git a/tests/libtest-core.sh b/tests/libtest-core.sh new file mode 100644 index 0000000..64b3e0a --- /dev/null +++ b/tests/libtest-core.sh @@ -0,0 +1,163 @@ +# Core source library for shell script tests; the +# canonical version lives in: +# +# https://github.com/ostreedev/ostree +# +# Known copies are in the following repos: +# +# - https://github.com/projectatomic/rpm-ostree +# +# Copyright (C) 2017 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +fatal() { + echo $@ 1>&2; exit 1 +} +# fatal() is shorter to type, but retain this alias +assert_not_reached () { + fatal "$@" +} + +# Some tests look for specific English strings. Use a UTF-8 version +# of the C (POSIX) locale if we have one, or fall back to en_US.UTF-8 +# (https://sourceware.org/glibc/wiki/Proposals/C.UTF-8) +# +# If we can't find the locale command assume we have support for C.UTF-8 +# (e.g. musl based systems) +if type -p locale >/dev/null; then + export LC_ALL=$(locale -a | grep -iEe '^(C|en_US)\.(UTF-8|utf8)$' | head -n1 || true) + if [ -z "${LC_ALL}" ]; then fatal "Can't find suitable UTF-8 locale"; fi +else + export LC_ALL=C.UTF-8 +fi +# A GNU extension, used whenever LC_ALL is not C +unset LANGUAGE + +# This should really be the default IMO +export G_DEBUG=fatal-warnings + +assert_streq () { + test "$1" = "$2" || fatal "$1 != $2" +} + +assert_str_match () { + if ! echo "$1" | grep -E -q "$2"; then + fatal "$1 does not match regexp $2" + fi +} + +assert_not_streq () { + (! test "$1" = "$2") || fatal "$1 == $2" +} + +assert_has_file () { + test -f "$1" || fatal "Couldn't find '$1'" +} + +assert_has_dir () { + test -d "$1" || fatal "Couldn't find '$1'" +} + +# Dump ls -al + file contents to stderr, then fatal() +_fatal_print_file() { + file="$1" + shift + ls -al "$file" >&2 + sed -e 's/^/# /' < "$file" >&2 + fatal "$@" +} + +assert_not_has_file () { + if test -f "$1"; then + _fatal_print_file "$1" "File '$1' exists" + fi +} + +assert_not_file_has_content () { + fpath=$1 + shift + for re in "$@"; do + if grep -q -e "$re" "$fpath"; then + _fatal_print_file "$fpath" "File '$fpath' matches regexp '$re'" + fi + done +} + +assert_not_has_dir () { + if test -d "$1"; then + fatal "Directory '$1' exists" + fi +} + +assert_file_has_content () { + fpath=$1 + shift + for re in "$@"; do + if ! grep -q -e "$re" "$fpath"; then + _fatal_print_file "$fpath" "File '$fpath' doesn't match regexp '$re'" + fi + done +} + +assert_file_has_content_once () { + fpath=$1 + shift + for re in "$@"; do + if ! test $(grep -e "$re" "$fpath" | wc -l) = "1"; then + _fatal_print_file "$fpath" "File '$fpath' doesn't match regexp '$re' exactly once" + fi + done +} + +assert_file_has_content_literal () { + fpath=$1; shift + for s in "$@"; do + if ! grep -q -F -e "$s" "$fpath"; then + _fatal_print_file "$fpath" "File '$fpath' doesn't match fixed string list '$s'" + fi + done +} + +assert_file_has_mode () { + mode=$(stat -c '%a' $1) + if [ "$mode" != "$2" ]; then + fatal "File '$1' has wrong mode: expected $2, but got $mode" + fi +} + +assert_symlink_has_content () { + if ! test -L "$1"; then + fatal "File '$1' is not a symbolic link" + fi + if ! readlink "$1" | grep -q -e "$2"; then + _fatal_print_file "$1" "Symbolic link '$1' doesn't match regexp '$2'" + fi +} + +assert_file_empty() { + if test -s "$1"; then + _fatal_print_file "$1" "File '$1' is not empty" + fi +} + +# Use to skip all of these tests +skip() { + echo "1..0 # SKIP" "$@" + exit 0 +} diff --git a/tests/libtest.sh b/tests/libtest.sh new file mode 100755 index 0000000..ca457fa --- /dev/null +++ b/tests/libtest.sh @@ -0,0 +1,790 @@ +# Source library for shell script tests +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +dn=$(dirname $0) + +if [ -n "${G_TEST_SRCDIR:-}" ]; then + test_srcdir="${G_TEST_SRCDIR}/tests" +else + test_srcdir=$(dirname $0) +fi + +if [ -n "${G_TEST_BUILDDIR:-}" ]; then + test_builddir="${G_TEST_BUILDDIR}/tests" +else + test_builddir=$(dirname $0) +fi +. ${test_srcdir}/libtest-core.sh + +# Array of expressions to execute when exiting. Each expression should +# be a single string (quoting if necessary) that will be eval'd. To add +# a command to run on exit, append to the libtest_exit_cmds array like +# libtest_exit_cmds+=(expr). +libtest_exit_cmds=() +run_exit_cmds() { + for expr in "${libtest_exit_cmds[@]}"; do + eval "${expr}" || true + done +} +trap run_exit_cmds EXIT + +save_core() { + if [ -e core ]; then + cp core "$test_srcdir/core" + fi +} +libtest_exit_cmds+=(save_core) + +test_tmpdir=$(pwd) + +# Sanity check that we're in a tmpdir that has +# just .testtmp (created by tap-driver for `make check`, +# or nothing at all (as ginstest-runner does) +if ! test -f .testtmp; then + files=$(ls) + if test -n "${files}"; then + ls -l + assert_not_reached "test tmpdir=${test_tmpdir} is not empty; run this test via \`make check TESTS=\`, not directly" + fi + # Remember that this is an acceptable test $(pwd), for the benefit of + # C and JS tests which may source this file again + touch .testtmp +fi + +# Also, unbreak `tar` inside `make check`...Automake will inject +# TAR_OPTIONS: --owner=0 --group=0 --numeric-owner presumably so that +# tarballs are predictable, except we don't want this in our tests. +unset TAR_OPTIONS + +# Don't flag deployments as immutable so that test harnesses can +# easily clean up. +export OSTREE_SYSROOT_DEBUG=mutable-deployments + +export TEST_GPG_KEYID_1="7FCA23D8472CDAFA" +export TEST_GPG_KEYFPR_1="5E65DE75AB1C501862D476347FCA23D8472CDAFA" +export TEST_GPG_KEYID_2="D8228CFECA950D41" +export TEST_GPG_KEYFPR_2="7B3B1020D74479687FDB2273D8228CFECA950D41" +export TEST_GPG_KEYID_3="0D15FAE7DF444D67" +export TEST_GPG_KEYFPR_3="7D29CF060B8269CDF63BFBDD0D15FAE7DF444D67" + +# GPG when creating signatures demands a private writable +# homedir in order to create lockfiles. Work around +# this by copying locally. +echo "Copying gpghome to ${test_tmpdir}" +cp -a "${test_srcdir}/gpghome" ${test_tmpdir} +chmod -R u+w "${test_tmpdir}" +chmod 700 "${test_tmpdir}/gpghome" +export TEST_GPG_KEYHOME=${test_tmpdir}/gpghome +export OSTREE_GPG_HOME=${test_tmpdir}/gpghome/trusted + +assert_has_setfattr() { + if ! which setfattr 2>/dev/null; then + fatal "no setfattr available to determine xattr support" + fi +} + +_have_selinux_relabel='' +have_selinux_relabel() { + assert_has_setfattr + if test "${_have_selinux_relabel}" = ''; then + pushd ${test_tmpdir} + echo testlabel > testlabel.txt + selinux_xattr=security.selinux + if getfattr --encoding=base64 -n ${selinux_xattr} testlabel.txt >label.txt 2>err.txt; then + label=$(grep -E -e "^${selinux_xattr}=" < label.txt |sed -e "s,${selinux_xattr}=,,") + if setfattr -n ${selinux_xattr} -v ${label} testlabel.txt 2>err.txt; then + echo "SELinux enabled in $(pwd), and have privileges to relabel" + _have_selinux_relabel=yes + else + sed -e 's/^/# /' < err.txt >&2 + echo "Found SELinux label, but unable to set (Unprivileged Docker?)" + _have_selinux_relabel=no + fi + else + sed -e 's/^/# /' < err.txt >&2 + echo "Unable to retrieve SELinux label, assuming disabled" + _have_selinux_relabel=no + fi + popd + fi + test ${_have_selinux_relabel} = yes +} + +# just globally turn off xattrs if we can't manipulate security xattrs; this is +# the case for overlayfs -- really, we should only enforce this for tests that +# use bare repos; separate from other tests that should check for user xattrs +# support +# see https://github.com/ostreedev/ostree/issues/758 +# and https://github.com/ostreedev/ostree/pull/1217 +echo -n checking for xattrs... +if ! have_selinux_relabel; then + export OSTREE_SYSROOT_DEBUG="${OSTREE_SYSROOT_DEBUG},no-xattrs" + export OSTREE_NO_XATTRS=1 +fi +echo done + +if test -n "${OT_TESTS_DEBUG:-}"; then + set -x +fi + +# This is substituted by the build for installed tests +BUILT_WITH_ASAN="" + +if test -n "${OT_TESTS_VALGRIND:-}"; then + CMD_PREFIX="env G_SLICE=always-malloc OSTREE_SUPPRESS_SYNCFS=1 valgrind -q --error-exitcode=1 --leak-check=full --num-callers=30 --suppressions=${test_srcdir}/glib.supp --suppressions=${test_srcdir}/ostree.supp" +else + # In some cases the LD_PRELOAD may cause obscure problems, + # e.g. right now it breaks for me with -fsanitize=address, so + # let's allow users to skip it. + if test -z "${OT_SKIP_READDIR_RAND:-}" && test -z "${BUILT_WITH_ASAN:-}"; then + CMD_PREFIX="env LD_PRELOAD=${test_builddir}/libreaddir-rand.so" + else + CMD_PREFIX="" + fi +fi + +if test -n "${OSTREE_UNINSTALLED:-}"; then + OSTREE_HTTPD=${OSTREE_UNINSTALLED}/ostree-trivial-httpd +else + # trivial-httpd is now in $libexecdir by default, which we don't + # know at this point. Fortunately, libtest.sh is also in + # $libexecdir, so make an educated guess. If it's not found, assume + # it's still runnable as "ostree trivial-httpd". + if [ -x "${test_srcdir}/../../libostree/ostree-trivial-httpd" ]; then + OSTREE_HTTPD="${CMD_PREFIX} ${test_srcdir}/../../libostree/ostree-trivial-httpd" + else + OSTREE_HTTPD="${CMD_PREFIX} ostree trivial-httpd" + fi +fi + +files_are_hardlinked() { + inode1=$(stat -c %i $1) + inode2=$(stat -c %i $2) + test -n "${inode1}" && test -n "${inode2}" + [ "${inode1}" == "${inode2}" ] +} + +assert_files_hardlinked() { + if ! files_are_hardlinked "$1" "$2"; then + fatal "Files '$1' and '$2' are not hardlinked" + fi +} + +setup_test_repository () { + mode=$1 + shift + + oldpwd=`pwd` + + COMMIT_ARGS="" + if [ $mode == "bare-user-only" ] ; then + COMMIT_ARGS="--owner-uid=0 --owner-gid=0 --no-xattrs --canonical-permissions" + fi + + cd ${test_tmpdir} + rm -rf repo + if test -n "${mode}"; then + ostree_repo_init repo --mode=${mode} + else + ostree_repo_init repo + fi + ot_repo="--repo=$(pwd)/repo" + export OSTREE="${CMD_PREFIX} ostree ${ot_repo}" + + cd ${test_tmpdir} + local oldumask="$(umask)" + umask 022 + rm -rf files + mkdir files + cd files + ot_files=`pwd` + export ht_files + ln -s nosuchfile somelink + echo first > firstfile + + cd ${test_tmpdir}/files + $OSTREE commit ${COMMIT_ARGS} -b test2 -s "Test Commit 1" -m "Commit body first" + + mkdir baz + echo moo > baz/cow + echo mooro > baz/cowro + chmod 600 baz/cowro + echo alien > baz/saucer + mkdir baz/deeper + echo hi > baz/deeper/ohyeah + echo hix > baz/deeper/ohyeahx + chmod 755 baz/deeper/ohyeahx + ln -s nonexistent baz/alink + mkdir baz/another/ + echo x > baz/another/y + umask "${oldumask}" + + cd ${test_tmpdir}/files + $OSTREE commit ${COMMIT_ARGS} -b test2 -s "Test Commit 2" -m "Commit body second" + $OSTREE fsck -q + + cd $oldpwd +} + +# A wrapper which also possibly disables xattrs for CI testing +ostree_repo_init() { + repo=$1 + shift + ${CMD_PREFIX} ostree --repo=${repo} init "$@" + if test -n "${OSTREE_NO_XATTRS:-}"; then + echo -e 'disable-xattrs=true\n' >> ${repo}/config + fi +} + +# The original one; use setup_fake_remote_repo2 for newer code, +# down the line we'll try to port tests. +setup_fake_remote_repo1() { + mode=$1; shift + commit_opts=${1:-} + [ $# -eq 0 ] || shift + oldpwd=`pwd` + mkdir ostree-srv + cd ostree-srv + mkdir gnomerepo + ostree_repo_init gnomerepo --mode=$mode + mkdir gnomerepo-files + cd gnomerepo-files + echo first > firstfile + mkdir baz + echo moo > baz/cow + echo alien > baz/saucer + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit $commit_opts --add-metadata-string version=3.0 -b main -s "A remote commit" -m "Some Commit body" + mkdir baz/deeper + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit $commit_opts --add-metadata-string version=3.1 -b main -s "Add deeper" + echo hi > baz/deeper/ohyeah + mkdir baz/another/ + echo x > baz/another/y + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit $commit_opts --add-metadata-string version=3.2 -b main -s "The rest" + cd .. + rm -rf gnomerepo-files + + cd ${test_tmpdir} + mkdir ${test_tmpdir}/httpd + cd httpd + ln -s ${test_tmpdir}/ostree-srv ostree + ${OSTREE_HTTPD} --autoexit --log-file $(pwd)/httpd.log --daemonize -p ${test_tmpdir}/httpd-port "$@" + port=$(cat ${test_tmpdir}/httpd-port) + echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address + cd ${oldpwd} + + export OSTREE="${CMD_PREFIX} ostree --repo=repo" +} + +# Newer version of the above with more "real" data +setup_fake_remote_repo2() { + mode=$1 + commit_opts=${2:-} + args=${3:-} + shift + oldpwd=`pwd` + mkdir ostree-srv + cd ostree-srv + mkdir repo + ostree_repo_init repo --mode=$mode + # Backcompat + ln -sr repo gnomerepo + # Initialize content + mkdir files + cd files + mkdir -p usr/{etc,bin,lib,share} + ln -sr usr/bin bin + ln -sr usr/lib lib + tar xf ${test_srcdir}/fah-deltadata-old.tar.xz + remote_ref=exampleos/42/x86_64/main + cd .. + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/repo commit \ + --consume $commit_opts --add-metadata-string version=42.0 -b ${remote_ref} \ + --tree=dir=files + test '!' -d files + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/repo checkout -U ${remote_ref} files + (cd files && tar xf ${test_srcdir}/fah-deltadata-new.tar.xz) + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/repo commit \ + --consume $commit_opts --add-metadata-string version=42.1 -b ${remote_ref} \ + --tree=dir=files + + # And serve via HTTP + cd ${test_tmpdir} + mkdir ${test_tmpdir}/httpd + cd httpd + ln -s ${test_tmpdir}/ostree-srv ostree + ${OSTREE_HTTPD} --autoexit --log-file $(pwd)/httpd.log --daemonize -p ${test_tmpdir}/httpd-port $args + port=$(cat ${test_tmpdir}/httpd-port) + echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address + cd ${oldpwd} + export OSTREE="${CMD_PREFIX} ostree --repo=repo" +} + +setup_os_boot_syslinux() { + # Stub syslinux configuration + mkdir -p sysroot/boot/loader.0 + ln -s loader.0 sysroot/boot/loader + touch sysroot/boot/loader/syslinux.cfg + # And a compatibility symlink + mkdir -p sysroot/boot/syslinux + ln -s ../loader/syslinux.cfg sysroot/boot/syslinux/syslinux.cfg +} + +setup_os_boot_uboot() { + # Stub U-Boot configuration + mkdir -p sysroot/boot/loader.0 + ln -s loader.0 sysroot/boot/loader + touch sysroot/boot/loader/uEnv.txt + # And a compatibility symlink + ln -s loader/uEnv.txt sysroot/boot/uEnv.txt +} + +setup_os_boot_grub2() { + grub2_options=$1 + mkdir -p sysroot/boot/grub2/ + ln -s ../loader/grub.cfg sysroot/boot/grub2/grub.cfg + export OSTREE_BOOT_PARTITION="/boot" + case "$grub2_options" in + *ostree-grub-generator*) + cp ${test_srcdir}/ostree-grub-generator ${test_tmpdir} + chmod +x ${test_tmpdir}/ostree-grub-generator + export OSTREE_GRUB2_EXEC=${test_tmpdir}/ostree-grub-generator + ;; + esac +} + +setup_os_boot_configured_bootloader() { + bootloader_keyval=$1 + ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set ${bootloader_keyval} +} + +setup_os_repository () { + mode=$1 + shift + bootmode=$1 + shift + bootdir=${1:-usr/lib/modules/3.6.0} + + oldpwd=`pwd` + + cd ${test_tmpdir} + mkdir testos-repo + if test -n "$mode"; then + ostree_repo_init testos-repo --mode=${mode} + else + ostree_repo_init testos-repo + fi + + cd ${test_tmpdir} + mkdir osdata + cd osdata + kver=3.6.0 + mkdir -p usr/bin ${bootdir} usr/lib/modules/${kver} usr/share usr/etc + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs.img + # the HMAC file is only in /usr/lib/modules + hmac_path=usr/lib/modules/${kver}/.vmlinuz.hmac + # /usr/lib/modules just uses "vmlinuz", since the version is in the module + # directory name. + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-${kver} + initramfs_path=${bootdir}/initramfs-${kver}.img + fi + echo "a kernel" > ${kernel_path} + echo "an initramfs" > ${initramfs_path} + echo "an hmac file" > ${hmac_path} + bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ') + export bootcsum + # Add the checksum for legacy dirs (/boot, /usr/lib/ostree-boot), but not + # /usr/lib/modules. + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} + fi + + echo "an executable" > usr/bin/sh + echo "some shared data" > usr/share/langs.txt + echo "a library" > usr/lib/libfoo.so.0 + ln -s usr/bin bin +cat > usr/etc/os-release < usr/etc/aconfigfile + mkdir -p usr/etc/NetworkManager + echo "a default daemon file" > usr/etc/NetworkManager/nm.conf + mkdir -p usr/etc/testdirectory + echo "a default daemon file" > usr/etc/testdirectory/test + + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build" + + # Ensure these commits have distinct second timestamps + sleep 2 + echo "a new executable" > usr/bin/sh + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.10 -b testos/buildmaster/x86_64-runtime -s "Build" + + cd ${test_tmpdir} + rm -rf osdata-devel + mkdir osdata-devel + tar -C osdata -cf - . | tar -C osdata-devel -xf - + cd osdata-devel + mkdir -p usr/include + echo "a development header" > usr/include/foo.h + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-devel -s "Build" + + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo fsck -q + + cd ${test_tmpdir} + mkdir sysroot + export OSTREE_SYSROOT=sysroot + ${CMD_PREFIX} ostree admin init-fs sysroot + if test -n "${OSTREE_NO_XATTRS:-}"; then + echo -e 'disable-xattrs=true\n' >> sysroot/ostree/repo/config + fi + ${CMD_PREFIX} ostree admin os-init testos + + case $bootmode in + "syslinux") + setup_os_boot_syslinux + ;; + "uboot") + setup_os_boot_uboot + ;; + *grub2*) + setup_os_boot_grub2 "${bootmode}" + ;; + sysroot\.bootloader*) + setup_os_boot_configured_bootloader "${bootmode}" + ;; + esac + + cd ${test_tmpdir} + mkdir ${test_tmpdir}/httpd + cd httpd + ln -s ${test_tmpdir} ostree + ${OSTREE_HTTPD} --autoexit --daemonize -p ${test_tmpdir}/httpd-port + port=$(cat ${test_tmpdir}/httpd-port) + echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address + cd ${oldpwd} +} + +timestamp_of_commit() +{ + date --date="$(ostree --repo=$1 show $2 | grep -Ee '^Date: ' | sed -e 's,^Date: *,,')" '+%s' +} + +os_repository_new_commit () +{ + boot_checksum_iteration=${1:-0} + content_iteration=${2:-0} + branch=${3:-testos/buildmaster/x86_64-runtime} + export version=${4:-$(date "+%Y%m%d.${content_iteration}")} + echo "BOOT ITERATION: $boot_checksum_iteration" + cd ${test_tmpdir}/osdata + kver=3.6.0 + if test -f usr/lib/modules/${kver}/vmlinuz; then + bootdir=usr/lib/modules/${kver} + else + if test -d usr/lib/ostree-boot; then + bootdir=usr/lib/ostree-boot + else + bootdir=boot + fi + fi + rm ${bootdir}/* + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs.img + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-${kver} + initramfs_path=${bootdir}/initramfs-${kver}.img + fi + echo "new: a kernel ${boot_checksum_iteration}" > ${kernel_path} + echo "new: an initramfs ${boot_checksum_iteration}" > ${initramfs_path} + bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ') + export bootcsum + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} + fi + + echo "a new default config file" > usr/etc/a-new-default-config-file + mkdir -p usr/etc/new-default-dir + echo "a new default dir and file" > usr/etc/new-default-dir/moo + + echo "content iteration ${content_iteration}" > usr/bin/content-iteration + + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string "version=${version}" -b $branch -s "Build" + if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo rev-parse ${branch} 2>/dev/null; then + prevdate=$(timestamp_of_commit ${test_tmpdir}/testos-repo "${branch}"^) + newdate=$(timestamp_of_commit ${test_tmpdir}/testos-repo "${branch}") + if [ $((${prevdate} > ${newdate})) = 1 ]; then + fatal "clock skew detected writing commits: prev=${prevdate} new=${newdate}" + fi + fi + cd ${test_tmpdir} +} + +_have_user_xattrs='' +have_user_xattrs() { + assert_has_setfattr + if test "${_have_user_xattrs}" = ''; then + touch test-xattrs + if setfattr -n user.testvalue -v somevalue test-xattrs 2>/dev/null; then + _have_user_xattrs=yes + else + _have_user_xattrs=no + fi + rm -f test-xattrs + fi + test ${_have_user_xattrs} = yes +} + +# Usage: if ! skip_one_without_user_xattrs; then ... more tests ...; fi +skip_one_without_user_xattrs () { + if ! have_user_xattrs; then + echo "ok # SKIP - this test requires xattr support" + return 0 + else + return 1 + fi +} + +skip_without_user_xattrs () { + if ! have_user_xattrs; then + skip "this test requires xattr support" + fi +} + +_have_systemd_and_libmount='' +have_systemd_and_libmount() { + if test "${_have_systemd_and_libmount}" = ''; then + if [ $(ostree --version | grep -c -e '- systemd' -e '- libmount') -eq 2 ]; then + _have_systemd_and_libmount=yes + else + _have_systemd_and_libmount=no + fi + fi + test ${_have_systemd_and_libmount} = yes +} + +# Skip unless SELinux is disabled, or we can relabel. +# Default Docker has security.selinux xattrs, but returns +# EOPNOTSUPP when trying to set them, even to the existing value. +# https://github.com/ostreedev/ostree/pull/759 +# https://github.com/ostreedev/ostree/pull/1217 +skip_without_no_selinux_or_relabel () { + if ! have_selinux_relabel; then + skip "this test requires xattr support" + fi +} + +# https://brokenpi.pe/tools/strace-fault-injection +_have_strace_fault_injection='' +have_strace_fault_injection() { + if test "${_have_strace_fault_injection}" = ''; then + if strace -P ${test_srcdir}/libtest-core.sh -e inject=read:retval=0 cat ${test_srcdir}/libtest-core.sh >out.txt && + test '!' -s out.txt; then + _have_strace_fault_injection=yes + else + _have_strace_fault_injection=no + fi + rm -f out.txt + fi + test ${_have_strace_fault_injection} = yes +} + +skip_one_without_strace_fault_injection() { + if ! have_strace_fault_injection; then + echo "ok # SKIP this test requires strace fault injection" + return 0 + fi + return 1 +} + +skip_without_fuse () { + fusermount --version >/dev/null 2>&1 || skip "no fusermount" + + capsh --print | grep -q 'Bounding set.*[^a-z]cap_sys_admin' || \ + skip "No cap_sys_admin in bounding set, can't use FUSE" + + [ -w /dev/fuse ] || skip "no write access to /dev/fuse" + [ -e /etc/mtab ] || skip "no /etc/mtab" +} + +skip_without_experimental () { + if ! ostree --version | grep -q -e '- experimental'; then + skip "No experimental API is compiled in" + fi +} + +has_gpgme () { + local ret + ${CMD_PREFIX} ostree --version > version.txt + grep -q -e '- gpgme' version.txt + ret=$? + rm -f version.txt + return ${ret} +} + +skip_without_gpgme() { + if ! has_gpgme; then + skip "no gpg support compiled in" + fi +} + +# Find an appropriate gpg program to use. We want one that has the +# --generate-key, --quick-set-expire and --quick-add-key options. The +# gpg program to use is returend. +which_gpg () { + local gpg + local gpg_options + local needed_options=( + --generate-key + --quick-set-expire + --quick-add-key + ) + local opt + + # Prefer gpg2 in case gpg refers to gpg1 + if which gpg2 &>/dev/null; then + gpg=gpg2 + elif which gpg &>/dev/null; then + gpg=gpg + else + # Succeed but don't return anything. + return 0 + fi + + # Make sure all the needed options are available + gpg_options=$(${gpg} --dump-options) || return 0 + for opt in ${needed_options[*]}; do + grep -q -x -e "${opt}" <<< "${gpg_options}" || return 0 + done + + # Found an appropriate gpg + echo ${gpg} +} + +libtest_cleanup_gpg () { + local gpg_homedir=${1:-${test_tmpdir}/gpghome} + gpg-connect-agent --homedir "${gpg_homedir}" killagent /bye || true +} +libtest_exit_cmds+=(libtest_cleanup_gpg) + +has_sign_ed25519 () { + local ret + ${CMD_PREFIX} ostree --version > version.txt + grep -q -e '- sign-ed25519' version.txt + ret=$? + rm -f version.txt + return ${ret} +} + +# Keys for ed25519 signing tests +ED25519PUBLIC= +ED25519SEED= +ED25519SECRET= + +gen_ed25519_keys () +{ + # Generate private key in PEM format + pemfile="$(mktemp -p ${test_tmpdir} ed25519_XXXXXX.pem)" + openssl genpkey -algorithm ed25519 -outform PEM -out "${pemfile}" + + # Based on: http://openssl.6102.n7.nabble.com/ed25519-key-generation-td73907.html + # Extract the private and public parts from generated key. + ED25519PUBLIC="$(openssl pkey -outform DER -pubout -in ${pemfile} | tail -c 32 | base64)" + ED25519SEED="$(openssl pkey -outform DER -in ${pemfile} | tail -c 32 | base64)" + # Secret key is concantination of SEED and PUBLIC + ED25519SECRET="$(echo ${ED25519SEED}${ED25519PUBLIC} | base64 -d | base64 -w 0)" + + echo "Generated ed25519 keys:" + echo "public: ${ED25519PUBLIC}" + echo " seed: ${ED25519SEED}" +} + +gen_ed25519_random_public() +{ + openssl genpkey -algorithm ED25519 | openssl pkey -outform DER | tail -c 32 | base64 +} + +is_bare_user_only_repo () { + grep -q 'mode=bare-user-only' $1/config +} + +# Given a path to a file in a repo for a ref, print its checksum +ostree_file_path_to_checksum() { + repo=$1 + ref=$2 + path=$3 + $CMD_PREFIX ostree --repo=$repo ls -C $ref $path | awk '{ print $5 }' +} + +# Given an object checksum, print its relative file path +ostree_checksum_to_relative_object_path() { + repo=$1 + checksum=$2 + if grep -Eq -e '^mode=archive' ${repo}/config; then suffix=z; else suffix=''; fi + echo objects/${checksum:0:2}/${checksum:2}.file${suffix} +} + +# Given a path to a file in a repo for a ref, print the (relative) path to its +# object +ostree_file_path_to_relative_object_path() { + repo=$1 + ref=$2 + path=$3 + checksum=$(ostree_file_path_to_checksum $repo $ref $path) + test -n "${checksum}" + ostree_checksum_to_relative_object_path ${repo} ${checksum} +} + +# Given a path to a file in a repo for a ref, print the path to its object +ostree_file_path_to_object_path() { + repo=$1 + ref=$2 + path=$3 + relpath=$(ostree_file_path_to_relative_object_path $repo $ref $path) + echo ${repo}/${relpath} +} + +# Assert ref $2 in repo $1 has checksum $3. +assert_ref () { + assert_streq $(${CMD_PREFIX} ostree rev-parse --repo=$1 $2) $3 +} + +# Assert no ref named $2 is present in repo $1. +assert_not_ref () { + if ${CMD_PREFIX} ostree rev-parse --repo=$1 $2 2>/dev/null; then + fatal "rev-parse $2 unexpectedly succeeded!" + fi +} + +assert_fail () { + set +e + $@ + if [ $? = 0 ] ; then + echo 1>&2 "$@ did not fail"; exit 1 + fi + set -euo pipefail +} diff --git a/tests/ostree-grub-generator b/tests/ostree-grub-generator new file mode 100644 index 0000000..d1436b6 --- /dev/null +++ b/tests/ostree-grub-generator @@ -0,0 +1,115 @@ +#!/bin/sh + +# The builtin grub.cfg generator. This script is called by +# ostree/src/libostree/ostree-bootloader-grub2.c whenever boot loader +# configuration file needs to be updated on systems which do not use +# grub2-mkconfig (and thus, the `ostree admin instutil grub2-generate` path). +# +# It can be used as a template for a custom grub.cfg generator. What to consider +# when writing a custom grub.cfg generator: +# +# - The populate_menu() function converts boot loader entries as defined by +# https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/ into GRUB2 +# menuentry sections. This is the core logic that is required by OSTree +# based system. +# +# - Embedded systems: Be aware that this script is executed not only on a host machine by OS +# installer, but also on a target device, thus think about shell portability. A target device +# for example might be using busybox with a limited shell. +# +# Feel free to edit this script to fit your requirements. + +set -e + +script=$(basename ${0}) +# Atomically safe location where to generete grub.cfg when executing system upgrade. +new_grub2_cfg=${2} +entries_path=$(dirname $new_grub2_cfg)/entries + +read_config() +{ + config_file=${1} + title="" + initrd="" + options="" + linux="" + devicetree="" + + while read -r line + do + record=$(echo ${line} | cut -f 1 -d ' ') + value=$(echo ${line} | cut -s -f2- -d ' ') + case "${record}" in + "title") + title=${value} + ;; + "initrd") + initrd=${value} + ;; + "linux") + linux=${value} + ;; + "devicetree") + devicetree=${value} + ;; + "options") + options=${value} + ;; + esac + done < ${config_file} + + if [ -z "${title}" ]; then + title="(Untitled)" + fi +} + +populate_menu() +{ + # Default to /boot if OSTREE_BOOT_PARTITION is not set and /boot is on the same device as /ostree/repo + if [ -z ${OSTREE_BOOT_PARTITION+x} ] && [ -d /boot/ostree ] && [ -d /ostree/repo ] && [ $(stat -c '%d' /boot/ostree) -eq $(stat -c '%d' /ostree/repo) ]; then + boot_prefix="/boot" + else + boot_prefix="${OSTREE_BOOT_PARTITION}" + fi + for config in $(ls -v -r $entries_path/*.conf); do + read_config ${config} + menu="${menu}menuentry '${title}' {\n" + menu="${menu}\t linux ${boot_prefix}${linux} ${options}\n" + if [ -n "${initrd}" ] ; then + menu="${menu}\t initrd ${boot_prefix}${initrd}\n" + fi + if [ -n "${devicetree}" ] ; then + menu="${menu}\t devicetree ${boot_prefix}${devicetree}\n" + fi + menu="${menu}}\n\n" + done + # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation + printf "$menu" >> ${new_grub2_cfg} +} + +populate_warning() +{ +cat >> ${new_grub2_cfg} <> ${new_grub2_cfg} < +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +function repo_init() { + cd ${test_tmpdir} + rm repo -rf + mkdir repo + ostree_repo_init repo --mode=${repo_mode} + ${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo "$@" +} + +repo_init --no-sign-verify + +# See also the copy of this in basic-test.sh +COMMIT_ARGS="" +CHECKOUT_U_ARG="" +CHECKOUT_H_ARGS="-H" +if is_bare_user_only_repo repo; then + COMMIT_ARGS="--canonical-permissions" + # Also, since we can't check out uid=0 files we need to check out in user mode + CHECKOUT_U_ARG="-U" + CHECKOUT_H_ARGS="-U -H" +else + if grep -E -q '^mode=bare-user' repo/config; then + CHECKOUT_H_ARGS="-U -H" + fi +fi + +function verify_initial_contents() { + rm checkout-origin-main -rf + $OSTREE checkout ${CHECKOUT_H_ARGS} origin/main checkout-origin-main + cd checkout-origin-main + assert_file_has_content firstfile '^first$' + assert_file_has_content baz/cow '^moo$' +} + +if has_gpgme; then + echo "1..35" +else + # 3 tests needs GPG support + echo "1..32" +fi + +# Try both syntaxes +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull origin main >out.txt +assert_file_has_content out.txt "[1-9][0-9]* metadata, [1-9][0-9]* content objects fetched; [1-9][0-9]*.*written" +${CMD_PREFIX} ostree --repo=repo pull origin:main > out.txt +assert_not_file_has_content out.txt "[1-9][0-9]* content objects fetched" +${CMD_PREFIX} ostree --repo=repo fsck +echo "ok pull" + +cd ${test_tmpdir} +verify_initial_contents +echo "ok pull contents" + +# And a test with incremental fsync +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull --per-object-fsync origin main >out.txt +assert_file_has_content out.txt "[1-9][0-9]* metadata, [1-9][0-9]* content objects fetched" +${CMD_PREFIX} ostree --repo=repo pull --per-object-fsync origin:main > out.txt +assert_not_file_has_content out.txt "[1-9][0-9]* content objects fetched" +${CMD_PREFIX} ostree --repo=repo fsck +verify_initial_contents +echo "ok pull --per-object-fsync" + +cd ${test_tmpdir} +mkdir mirrorrepo +ostree_repo_init mirrorrepo --mode=archive +${CMD_PREFIX} ostree --repo=mirrorrepo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=mirrorrepo pull --mirror origin main +${CMD_PREFIX} ostree --repo=mirrorrepo fsck +$OSTREE show main >/dev/null +echo "ok pull mirror" + +mkdir otherbranch +echo someothercontent > otherbranch/someothercontent +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b otherbranch --tree=dir=otherbranch +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +rm mirrorrepo -rf +# All refs +ostree_repo_init mirrorrepo --mode=archive +${CMD_PREFIX} ostree --repo=mirrorrepo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=mirrorrepo pull --mirror origin +${CMD_PREFIX} ostree --repo=mirrorrepo fsck +for ref in main otherbranch; do + ${CMD_PREFIX} ostree --repo=mirrorrepo rev-parse $ref +done +echo "ok pull mirror (all refs)" + +rm mirrorrepo -rf +ostree_repo_init mirrorrepo --mode=archive +${CMD_PREFIX} ostree --repo=mirrorrepo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +# Generate a summary in the mirror +${CMD_PREFIX} ostree --repo=mirrorrepo summary -u +summarysig=$(sha256sum < mirrorrepo/summary | cut -f 1 -d ' ') +# Mirror subset of refs: https://github.com/ostreedev/ostree/issues/846 +${CMD_PREFIX} ostree --repo=mirrorrepo pull --mirror origin main +newsummarysig=$(sha256sum < mirrorrepo/summary | cut -f 1 -d ' ') +assert_streq ${summarysig} ${newsummarysig} +echo "ok pull mirror (ref subset with summary)" + +cd ${test_tmpdir} +rm checkout-origin-main -rf +$OSTREE --repo=ostree-srv/gnomerepo checkout ${CHECKOUT_U_ARG} main checkout-origin-main +echo moomoo > checkout-origin-main/baz/cow +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main -s "" --tree=dir=checkout-origin-main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo static-delta generate main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo fsck +${CMD_PREFIX} ostree --repo=mirrorrepo pull --mirror origin main +${CMD_PREFIX} ostree --repo=mirrorrepo fsck +echo "ok pull mirror (should not apply deltas)" + +cd ${test_tmpdir} +if ${CMD_PREFIX} ostree --repo=mirrorrepo \ + pull origin main --require-static-deltas 2>err.txt; then + assert_not_reached "--require-static-deltas unexpectedly succeeded" +fi +assert_file_has_content err.txt "Can't use static deltas in an archive repo" +${CMD_PREFIX} ostree --repo=mirrorrepo pull origin main +${CMD_PREFIX} ostree --repo=mirrorrepo fsck +echo "ok pull (refuses deltas)" + +cd ${test_tmpdir} +rm mirrorrepo/refs/remotes/* -rf +${CMD_PREFIX} ostree --repo=mirrorrepo prune --refs-only +${CMD_PREFIX} ostree --repo=mirrorrepo pull --bareuseronly-files origin main +echo "ok pull (bareuseronly, safe)" + +rm checkout-origin-main -rf +$OSTREE --repo=ostree-srv/gnomerepo checkout ${CHECKOUT_U_ARG} main checkout-origin-main +cat > statoverride.txt < checkout-origin-main/some-setuid +# Don't use ${COMMIT_ARGS} as we don't want --canonical-permissions with bare-user-only +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit -b content-with-suid --statoverride=statoverride.txt --tree=dir=checkout-origin-main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +# Verify we reject it both when unpacking and when mirroring +for flag in "" "--mirror"; do + if ${CMD_PREFIX} ostree --repo=mirrorrepo pull ${flag} --bareuseronly-files origin content-with-suid 2>err.txt; then + assert_not_reached "pulled unsafe bareuseronly" + fi + assert_file_has_content err.txt 'Content object.*: invalid mode.*with bits 040.*' +done +echo "ok pull (bareuseronly, unsafe)" + +cd ${test_tmpdir} +rm mirrorrepo/refs/remotes/* -rf +${CMD_PREFIX} ostree --repo=mirrorrepo prune --refs-only +${CMD_PREFIX} ostree --repo=mirrorrepo pull --mirror --bareuseronly-files origin main +echo "ok pull (bareuseronly mirror)" + +# Corruption tests +cd ${test_tmpdir} +repo_init --no-sign-verify +if ! is_bare_user_only_repo repo; then +if ! skip_one_without_user_xattrs; then + if is_bare_user_only_repo repo; then + cacherepomode=bare-user-only + else + cacherepomode=bare-user + fi + rm cacherepo -rf + ostree_repo_init cacherepo --mode=${cacherepomode} + ${CMD_PREFIX} ostree --repo=cacherepo pull-local ostree-srv/gnomerepo main + rev=$(ostree --repo=cacherepo rev-parse main) + ${CMD_PREFIX} ostree --repo=cacherepo ls -R -C main > ls.txt + regfile_hash=$((grep -E -e '^-0' ls.txt || true) | head -1 | awk '{ print $5 }') + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false corruptrepo $(cat httpd-address)/ostree/corruptrepo + # Make this a loop so in the future we can add more object types like commit etc. + for object in ${regfile_hash}.file; do + checksum=$(echo ${object} | sed -e 's,\(.*\)\.[a-z]*$,\1,') + path=cacherepo/objects/${object:0:2}/${object:2} + # Preserve user.ostreemeta xattr + cp -a ${path}{,.new} + (dd if=${path} conv=swab) > ${path}.new + mv ${path}{.new,} + if ${CMD_PREFIX} ostree --repo=cacherepo fsck 2>err.txt; then + fatal "corrupt repo fsck?" + fi + assert_file_has_content err.txt "Corrupted.*${checksum}" + rm ostree-srv/corruptrepo -rf + ostree_repo_init ostree-srv/corruptrepo --mode=archive + ${CMD_PREFIX} ostree --repo=ostree-srv/corruptrepo pull-local cacherepo main + # Pulling via HTTP into a non-archive should fail, even with + # --http-trusted. + if ${CMD_PREFIX} ostree --repo=repo pull --http-trusted corruptrepo main 2>err.txt; then + fatal "Pulled from corrupt repo?" + fi + assert_file_has_content err.txt "Corrupted.*${checksum}" + if ${CMD_PREFIX} ostree --repo=repo show corruptrepo:main >/dev/null; then + fatal "Pulled from corrupt repo?" + fi + ${CMD_PREFIX} ostree --repo=repo prune --refs-only + rm repo/tmp/* -rf + ostree_repo_init corruptmirrorrepo --mode=archive + # Pulling via http-trusted should not verify the checksum + ${CMD_PREFIX} ostree --repo=corruptmirrorrepo remote add --set=gpg-verify=false corruptrepo $(cat httpd-address)/ostree/corruptrepo + ${CMD_PREFIX} ostree --repo=corruptmirrorrepo pull --mirror --http-trusted corruptrepo main + # But it should fail to fsck + if ${CMD_PREFIX} ostree --repo=corruptmirrorrepo fsck 2>err.txt; then + fatal "corrupt mirror repo fsck?" + fi + done + + # And ensure the repo is reinitialized + repo_init --no-sign-verify + echo "ok corruption" +fi +else +# bareuseronly case, we don't mark it as SKIP at the moment +echo "ok corruption (skipped)" +fi + + +cd ${test_tmpdir}/ostree-srv +tar xf ${test_srcdir}/ostree-path-traverse.tar.gz +cd ${test_tmpdir} +rm corruptrepo -rf +ostree_repo_init corruptrepo --mode=archive +${CMD_PREFIX} ostree --repo=corruptrepo remote add --set=gpg-verify=false pathtraverse $(cat httpd-address)/ostree/ostree-path-traverse/repo +if ${CMD_PREFIX} ostree --repo=corruptrepo pull pathtraverse pathtraverse-test 2>err.txt; then + fatal "Pulled a repo with path traversal in dirtree" +fi +assert_file_has_content_literal err.txt 'ae9a5d2701a02740aa2ee317ba53b13e3efb0f29609cd4896e1bafeee4caddb5.dirtree: Invalid / in filename ../afile' +# And verify we didn't write the object into the staging directory even +find corruptrepo/tmp -name '9a5d2701a02740aa2ee317ba53b13e3efb0f29609cd4896e1bafeee4caddb5.dirtree' >find.txt +assert_not_file_has_content find.txt '9a5d2701a02740aa2ee317ba53b13e3efb0f29609cd4896e1bafeee4caddb5' +rm corruptrepo -rf +echo "ok path traversal checked on pull" + + +cd ${test_tmpdir} +rm mirrorrepo/refs/remotes/* -rf +${CMD_PREFIX} ostree --repo=mirrorrepo prune --refs-only +${CMD_PREFIX} ostree --repo=mirrorrepo pull origin main +rm checkout-origin-main -rf +$OSTREE --repo=ostree-srv/gnomerepo checkout ${CHECKOUT_U_ARG} main checkout-origin-main +echo yetmorecontent > checkout-origin-main/baz/cowtest +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main -s "" --tree=dir=checkout-origin-main +rev=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo rev-parse main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo static-delta generate main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +${CMD_PREFIX} ostree --repo=mirrorrepo pull --commit-metadata-only origin main +assert_has_file mirrorrepo/state/${rev}.commitpartial +echo "ok pull commit metadata only (should not apply deltas)" + +cd ${test_tmpdir} +mkdir mirrorrepo-local +ostree_repo_init mirrorrepo-local --mode=archive +${CMD_PREFIX} ostree --repo=mirrorrepo-local remote add --set=gpg-verify=false origin file://$(pwd)/ostree-srv/gnomerepo +${CMD_PREFIX} ostree --repo=mirrorrepo-local pull --mirror origin main +${CMD_PREFIX} ostree --repo=mirrorrepo-local fsck +${CMD_PREFIX} ostree --repo=mirrorrepo show main >/dev/null +echo "ok pull local mirror" + +cd ${test_tmpdir} +# This is more of a known issue; test that we give a clean error right now +rm otherrepo -rf +ostree_repo_init otherrepo --mode=archive +rm checkout-origin-main -rf +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo checkout ${CHECKOUT_U_ARG} main checkout-origin-main +${CMD_PREFIX} ostree --repo=otherrepo commit ${COMMIT_ARGS} -b localbranch --tree=dir=checkout-origin-main +${CMD_PREFIX} ostree --repo=otherrepo remote add --set=gpg-verify=false origin file://$(pwd)/ostree-srv/gnomerepo +${CMD_PREFIX} ostree --repo=otherrepo pull origin main +rm mirrorrepo-local -rf +ostree_repo_init mirrorrepo-local --mode=archive +if ${CMD_PREFIX} ostree --repo=mirrorrepo-local pull-local otherrepo 2>err.txt; then + fatal "pull with mixed refs succeeded?" +fi +assert_file_has_content err.txt "error: Invalid ref name origin:main" +${CMD_PREFIX} ostree --repo=mirrorrepo-local pull-local otherrepo localbranch +${CMD_PREFIX} ostree --repo=mirrorrepo-local rev-parse localbranch +${CMD_PREFIX} ostree --repo=mirrorrepo-local fsck +echo "ok pull-local mirror errors with mixed refs" + +rm -f otherrepo/summary +if ${CMD_PREFIX} ostree --repo=mirrorrepo-local pull-local otherrepo nosuchbranch 2>err.txt; then + fatal "pulled nonexistent branch" +fi +# So true +assert_file_has_content_literal err.txt "error: Refspec 'nosuchbranch' not found" +echo "ok pull-local nonexistent branch" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main -s "Metadata string" --add-detached-metadata-string=SIGNATURE=HANCOCK --tree=ref=main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo fsck +$OSTREE show --print-detached-metadata-key=SIGNATURE main > main-meta +assert_file_has_content main-meta "HANCOCK" +echo "ok pull detached metadata" + +cd ${test_tmpdir} +mkdir parentpullrepo +ostree_repo_init parentpullrepo --mode=archive +${CMD_PREFIX} ostree --repo=parentpullrepo remote add --set=gpg-verify=false origin file://$(pwd)/ostree-srv/gnomerepo +parent_rev=$(ostree --repo=ostree-srv/gnomerepo rev-parse main^) +rev=$(ostree --repo=ostree-srv/gnomerepo rev-parse main) +${CMD_PREFIX} ostree --repo=parentpullrepo pull origin main@${parent_rev} +${CMD_PREFIX} ostree --repo=parentpullrepo rev-parse origin:main > main.txt +assert_file_has_content main.txt ${parent_rev} +${CMD_PREFIX} ostree --repo=parentpullrepo fsck +${CMD_PREFIX} ostree --repo=parentpullrepo pull origin main +${CMD_PREFIX} ostree --repo=parentpullrepo rev-parse origin:main > main.txt +assert_file_has_content main.txt ${rev} +echo "ok pull specific commit" + +# test pull -T and --timestamp-check-from-rev +cd ${test_tmpdir} +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull origin main +origrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse main) +# Check we can pull the same commit with timestamp checking enabled +${CMD_PREFIX} ostree --repo=repo pull -T origin main +assert_streq ${origrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +newrev=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main --tree=ref=main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +# New commit with timestamp checking +${CMD_PREFIX} ostree --repo=repo pull -T origin main +assert_not_streq "${origrev}" "${newrev}" +assert_streq ${newrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +newrev2=$(${CMD_PREFIX} ostree --timestamp="October 25 1985" --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main --tree=ref=main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +if ${CMD_PREFIX} ostree --repo=repo pull -T origin main 2>err.txt; then + fatal "pulled older commit with timestamp checking enabled?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +assert_streq ${newrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +# And also check we can't pull it when using overrides +if ${CMD_PREFIX} ostree --repo=repo pull -T origin main@${newrev2} 2>err.txt; then + fatal "pulled older commit override with timestamp checking enabled?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +assert_streq ${newrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +# But we can pull it without timestamp checking +${CMD_PREFIX} ostree --repo=repo pull origin main +# Now test --timestamp-check-from-rev. First, add two new commits with distinct +# but newer timestamps. +oldrev=${newrev2} +middlerev=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main --tree=ref=main) +sleep 1 +latestrev=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main --tree=ref=main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +# OK, let's pull the latest now. +${CMD_PREFIX} ostree --repo=repo pull -T origin main +assert_streq ${latestrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +# Check we can't pull the middle commit by overrides with ts checking on +if ${CMD_PREFIX} ostree --repo=repo pull -T origin main@${middlerev} 2>err.txt; then + fatal "pulled older commit override with timestamp checking enabled?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +# Check we can't pull an older commit by override if it's newer than --timestamp-check-from-rev +if ${CMD_PREFIX} ostree --repo=repo pull --timestamp-check-from-rev=${latestrev} origin main@${middlerev} 2>err.txt; then + fatal "pulled older commit override with timestamp checking enabled?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +# But we can pull it with --timestamp-check-from-rev when starting from the oldrev +${CMD_PREFIX} ostree --repo=repo pull --timestamp-check-from-rev=${oldrev} origin main@${middlerev} +echo "ok pull timestamp checking" + +cd ${test_tmpdir} +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo fsck +# Generate a delta from old to current, even though we aren't going to +# use it. +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo static-delta generate main + +rm main-files -rf +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo checkout ${CHECKOUT_U_ARG} main main-files +cd main-files +echo "an added file for static deltas" > added-file +echo "modified file for static deltas" > baz/cow +rm baz/saucer +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main -s 'static delta test' +cd .. +rm main-files -rf +# Generate delta that we'll use +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo static-delta generate main +prev_rev=$(ostree --repo=ostree-srv/gnomerepo rev-parse main^) +new_rev=$(ostree --repo=ostree-srv/gnomerepo rev-parse main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + +# Explicitly test delta fetches via ref name as well as commit hash +for delta_target in main ${new_rev}; do +cd ${test_tmpdir} +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} +${CMD_PREFIX} ostree --repo=repo pull --dry-run --require-static-deltas origin ${delta_target} >dry-run-pull.txt +# Compression can vary, so we support 400-699 +delta_dry_run_regexp='Delta update: 0/1 parts, 0[  ]bytes/[456][0-9][0-9][  ]bytes, 455[  ]bytes total uncompressed' +assert_file_has_content dry-run-pull.txt "${delta_dry_run_regexp}" +rev=$(${CMD_PREFIX} ostree --repo=repo rev-parse origin:main) +assert_streq "${prev_rev}" "${rev}" +${CMD_PREFIX} ostree --repo=repo fsck +done + +# Test pull via file:/// - this should still use the deltas path for testing +cd ${test_tmpdir} +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo remote delete origin +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin file://$(pwd)/ostree-srv/gnomerepo +${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} +${CMD_PREFIX} ostree --repo=repo pull --dry-run --require-static-deltas origin ${delta_target} >dry-run-pull.txt +# See above +assert_file_has_content dry-run-pull.txt "${delta_dry_run_regexp}" +echo "ok pull file:// + deltas required" + +# Explicitly test delta fetches via ref name as well as commit hash +for delta_target in main ${new_rev}; do +cd ${test_tmpdir} +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} +${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin ${delta_target} +if test ${delta_target} = main; then + rev=$(${CMD_PREFIX} ostree --repo=repo rev-parse origin:main) + assert_streq "${new_rev}" "${rev}" +else + ${CMD_PREFIX} ostree --repo=repo rev-parse ${delta_target} +fi +${CMD_PREFIX} ostree --repo=repo fsck +done + +# Test no-op with deltas: https://github.com/ostreedev/ostree/issues/1321 +cd ${test_tmpdir} +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin main + +cd ${test_tmpdir} +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} +${CMD_PREFIX} ostree --repo=repo pull --disable-static-deltas origin main +${CMD_PREFIX} ostree --repo=repo fsck + +rm checkout-origin-main -rf +$OSTREE checkout ${CHECKOUT_H_ARGS} origin:main checkout-origin-main +cd checkout-origin-main +assert_file_has_content firstfile '^first$' +assert_file_has_content baz/cow "modified file for static deltas" +assert_not_has_file baz/saucer + +echo "ok static delta" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo static-delta generate --swap-endianness main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} +${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas --dry-run origin main >byteswapped-dry-run-pull.txt +${CMD_PREFIX} ostree --repo=repo fsck + +if ! diff -u dry-run-pull.txt byteswapped-dry-run-pull.txt; then + assert_not_reached "byteswapped delta differs in size" +fi + +echo "ok pull byteswapped delta" + +cd ${test_tmpdir} +rm ostree-srv/gnomerepo/deltas -rf +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +repo_init --no-sign-verify +if ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin main 2>err.txt; then + assert_not_reached "--require-static-deltas unexpectedly succeeded" +fi +assert_file_has_content err.txt "deltas required, but none found" +${CMD_PREFIX} ostree --repo=repo fsck + +# Now test with a partial commit +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull --commit-metadata-only origin main@${prev_rev} +if ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin main 2>err.txt; then + assert_not_reached "--require-static-deltas unexpectedly succeeded" +fi +assert_file_has_content err.txt "deltas required, but none found" +echo "ok delta required but don't exist" + +repo_init --no-sign-verify +${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} +if ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin ${new_rev} 2>err.txt; then + assert_not_reached "--require-static-deltas unexpectedly succeeded" +fi +assert_file_has_content err.txt "deltas required, but none found" +echo "ok delta required for revision" + +cd ${test_tmpdir} +rm main-files -rf +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo checkout ${CHECKOUT_U_ARG} main main-files +cd main-files +echo "more added files for static deltas" > added-file2 +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main -s 'inline static delta test' +cd .. +rm main-files -rf +# Generate new delta that we'll use +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo static-delta generate --inline main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo fsck + +rm checkout-origin-main -rf +$OSTREE checkout ${CHECKOUT_H_ARGS} origin:main checkout-origin-main +cd checkout-origin-main +assert_file_has_content added-file2 "more added files for static deltas" + +echo "ok inline static delta" + +cd ${test_tmpdir} +rm main-files -rf +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo checkout ${CHECKOUT_U_ARG} main main-files +cd main-files +# Make a file larger than 16M for testing +dd if=/dev/zero of=test-bigfile count=1 seek=42678 +echo "further modified file for static deltas" > baz/cow +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_ARGS} -b main -s '2nd static delta test' +cd .. +rm main-files -rf +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo static-delta generate main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo fsck + +rm checkout-origin-main -rf +$OSTREE checkout ${CHECKOUT_H_ARGS} origin:main checkout-origin-main +cd checkout-origin-main +assert_has_file test-bigfile +stat --format=%s test-bigfile > bigfile-size +assert_file_has_content bigfile-size 21851648 +assert_file_has_content baz/cow "further modified file for static deltas" +assert_not_has_file baz/saucer + +echo "ok static delta 2" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=repo pull origin main main@${rev} main@${rev} main main@${rev} main +echo "ok pull specific commit array" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false --set=unconfigured-state="Access to ExampleOS requires ONE BILLION DOLLARS." origin-subscription file://$(pwd)/ostree-srv/gnomerepo +if ${CMD_PREFIX} ostree --repo=repo pull origin-subscription main 2>err.txt; then + assert_not_reached "pull unexpectedly succeeded?" +fi +assert_file_has_content err.txt "ONE BILLION DOLLARS" + +echo "ok unconfigured" + +cd ${test_tmpdir} +repo_init +${CMD_PREFIX} ostree --repo=repo remote add origin-bad $(cat httpd-address)/ostree/noent +if ${CMD_PREFIX} ostree --repo=repo --depth=0 pull origin-bad main 2>err.txt; then + assert_not_reached "pull repo 404 succeeded?" +fi +assert_file_has_content err.txt "404" +echo "ok pull repo 404" + +if has_gpgme; then + cd ${test_tmpdir} + repo_init --set=gpg-verify=true + if ${CMD_PREFIX} ostree --repo=repo --depth=0 pull origin main 2>err.txt; then + assert_not_reached "pull repo 404 succeeded?" + fi + assert_file_has_content err.txt "GPG verification enabled, but no signatures found" + echo "ok pull repo 404 (gpg)" +fi + +cd ${test_tmpdir} +find ostree-srv/gnomerepo/objects -name '*.dirtree' | while read f; do mv ${f}{,.orig}; done +repo_init --set=gpg-verify=false +if ${CMD_PREFIX} ostree --repo=repo --depth=0 pull origin main 2>err.txt; then + assert_not_reached "pull repo 404 succeeded?" +fi +assert_file_has_content err.txt "404" +find ostree-srv/gnomerepo/objects -name '*.dirtree.orig' | while read f; do mv ${f} $(dirname $f)/$(basename ${f} .orig); done +echo "ok pull repo 404 on dirtree object" + +if has_gpgme; then + cd ${test_tmpdir} + repo_init --set=gpg-verify=true + ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} \ + --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1} -b main \ + -s "A signed commit" --tree=ref=main + ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + # make sure gpg verification is correctly on + csum=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo rev-parse main) + objpath=objects/${csum::2}/${csum:2}.commitmeta + remotesig=ostree-srv/gnomerepo/$objpath + localsig=repo/$objpath + mv $remotesig $remotesig.bak + if ${CMD_PREFIX} ostree --repo=repo --depth=0 pull origin main; then + assert_not_reached "pull with gpg-verify unexpectedly succeeded?" + fi + # ok now check that we can pull correctly + mv $remotesig.bak $remotesig + ${CMD_PREFIX} ostree --repo=repo pull origin main + echo "ok pull signed commit" + rm $localsig + ${CMD_PREFIX} ostree --repo=repo pull origin main + test -f $localsig + echo "ok re-pull signature for stored commit" +fi + +cd ${test_tmpdir} +repo_init --no-sign-verify +mv ostree-srv/gnomerepo/refs/heads/main{,.orig} +rm ostree-srv/gnomerepo/summary +(for x in $(seq 20); do echo "lots of html here "; done) > ostree-srv/gnomerepo/refs/heads/main +if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>err.txt; then + fatal "pull of invalid ref succeeded" +fi +assert_file_has_content_literal err.txt 'error: Fetching checksum for ref ((empty), main): Invalid rev lots of html here lots of html here lots of html here lots of' +echo "ok pull got HTML for a ref" diff --git a/tests/pull-test2.sh b/tests/pull-test2.sh new file mode 100644 index 0000000..a0b699a --- /dev/null +++ b/tests/pull-test2.sh @@ -0,0 +1,63 @@ +# This file is to be sourced, not executed + +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +function repo_init() { + cd ${test_tmpdir} + rm repo -rf + mkdir repo + ostree_repo_init repo --mode=${repo_mode} + ${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo "$@" +} + +repo_init --no-sign-verify + +# See also the copy of this in basic-test.sh +COMMIT_ARGS="" +CHECKOUT_U_ARG="" +CHECKOUT_H_ARGS="-H" +if is_bare_user_only_repo repo; then + COMMIT_ARGS="--canonical-permissions" + # Also, since we can't check out uid=0 files we need to check out in user mode + CHECKOUT_U_ARG="-U" + CHECKOUT_H_ARGS="-U -H" +else + if grep -E -q '^mode=bare-user' repo/config; then + CHECKOUT_H_ARGS="-U -H" + fi +fi + +echo "1..1" +cd ${test_tmpdir} +repo_init --no-sign-verify +prev_rev=$(ostree --repo=ostree-srv/repo rev-parse ${remote_ref}^) +rev=$(ostree --repo=ostree-srv/repo rev-parse ${remote_ref}) +${CMD_PREFIX} ostree --repo=ostree-srv/repo static-delta generate ${remote_ref} +${CMD_PREFIX} ostree --repo=ostree-srv/repo summary -u +${CMD_PREFIX} ostree --repo=repo pull origin ${remote_ref}@${prev_rev} +${CMD_PREFIX} ostree --repo=repo pull --dry-run --require-static-deltas origin ${remote_ref} >dry-run-pull.txt +assert_file_has_content dry-run-pull.txt 'Delta update: 0/1 parts, 0 bytes/[45][0-9]\.[0-9][  ]kB, 1\.[678][  ]MB total uncompressed' +${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin ${remote_ref} +final_rev=$(${CMD_PREFIX} ostree --repo=repo rev-parse origin:${remote_ref}) +assert_streq "${rev}" "${final_rev}" +${CMD_PREFIX} ostree --repo=repo fsck +echo "ok delta" diff --git a/tests/readdir-rand.c b/tests/readdir-rand.c new file mode 100644 index 0000000..64a7651 --- /dev/null +++ b/tests/readdir-rand.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2015 Colin Walters . + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Glibc uses readdir64 when _FILE_OFFSET_BITS == 64 as set by + * AC_SYS_LARGEFILE on 32 bit systems. + */ +#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64) +# define READDIR "readdir64" +# define READDIR_R "readdir64_r" +#else +# define READDIR "readdir" +# define READDIR_R "readdir_r" +#endif + +static GHashTable *direntcache; +static GMutex direntcache_lock; +static gsize initialized; + +typedef struct { + GPtrArray *entries; + guint offset; +} DirEntries; + +static void +dir_entries_free (gpointer data) +{ + DirEntries *d = data; + g_ptr_array_unref (d->entries); + g_free (d); +} + +static DirEntries * +dir_entries_new (void) +{ + DirEntries *d = g_new0 (DirEntries, 1); + d->entries = g_ptr_array_new_with_free_func (g_free); + return d; +} + +static void +ensure_initialized (void) +{ + if (g_once_init_enter (&initialized)) + { + direntcache = g_hash_table_new_full (NULL, NULL, NULL, dir_entries_free); + g_mutex_init (&direntcache_lock); + g_once_init_leave (&initialized, 1); + } +} + +struct dirent * +readdir (DIR *dirp) +{ + struct dirent *(*real_readdir)(DIR *dirp) = dlsym (RTLD_NEXT, READDIR); + struct dirent *ret; + gboolean cache_another = TRUE; + + ensure_initialized (); + + /* The core idea here is that each time through the loop, we read a + * directory entry. If there is one, we choose whether to cache it + * or to return it. Because multiple entries can be cached, + * ordering is randomized. Statistically, the order will still be + * *weighted* towards the ordering returned from the + * kernel/filesystem, but the goal here is just to provide some + * randomness in order to trigger bugs, not to be perfectly random. + */ + while (cache_another) + { + DirEntries *de; + + errno = 0; + ret = real_readdir (dirp); + if (ret == NULL && errno != 0) + goto out; + + g_mutex_lock (&direntcache_lock); + de = g_hash_table_lookup (direntcache, dirp); + if (ret) + { + if (g_random_boolean ()) + { + struct dirent *copy; + if (!de) + { + de = dir_entries_new (); + g_hash_table_insert (direntcache, dirp, de); + } + copy = g_memdup (ret, sizeof (struct dirent)); + g_ptr_array_add (de->entries, copy); + } + else + { + cache_another = FALSE; + } + } + else + { + if (de && de->offset < de->entries->len) + { + ret = de->entries->pdata[de->offset]; + de->offset++; + } + cache_another = FALSE; + } + g_mutex_unlock (&direntcache_lock); + } + + out: + return ret; +} + +int +closedir (DIR *dirp) +{ + int (*real_closedir)(DIR *dirp) = dlsym (RTLD_NEXT, "closedir"); + + ensure_initialized (); + + g_mutex_lock (&direntcache_lock); + g_hash_table_remove (direntcache, dirp); + g_mutex_unlock (&direntcache_lock); + + return real_closedir (dirp); +} + +static void +assert_no_cached_entries (DIR *dirp) +{ + DirEntries *de; + g_mutex_lock (&direntcache_lock); + de = g_hash_table_lookup (direntcache, dirp); + g_assert (!de || de->entries->len == 0); + g_mutex_unlock (&direntcache_lock); +} + +void +seekdir (DIR *dirp, long loc) +{ + void (*real_seekdir)(DIR *dirp, long loc) = dlsym (RTLD_NEXT, "seekdir"); + + ensure_initialized (); + + /* For now, crash if seekdir is called when we have cached entries. + * If some app wants to use this and seekdir() we can implement it. + */ + assert_no_cached_entries (dirp); + + real_seekdir (dirp, loc); +} + +void +rewinddir (DIR *dirp) +{ + void (*real_rewinddir)(DIR *dirp) = dlsym (RTLD_NEXT, "rewinddir"); + + ensure_initialized (); + + /* Blow away the cache */ + g_mutex_lock (&direntcache_lock); + g_hash_table_remove (direntcache, dirp); + g_mutex_unlock (&direntcache_lock); + + real_rewinddir (dirp); +} + +int +readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result) +{ + int (*real_readdir_r)(DIR *dirp, struct dirent *entry, struct dirent **result) = dlsym (RTLD_NEXT, READDIR_R); + + ensure_initialized (); + + /* For now, assert that no one is mixing readdir_r() with readdir(). + * It'd be broken to do so, and very few programs use readdir_r() + * anyways. */ + assert_no_cached_entries (dirp); + + return real_readdir_r (dirp, entry, result); +} diff --git a/tests/repo-finder-mount.c b/tests/repo-finder-mount.c new file mode 100644 index 0000000..2cb1d23 --- /dev/null +++ b/tests/repo-finder-mount.c @@ -0,0 +1,129 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-remote-private.h" +#include "ostree-repo-finder.h" +#include "ostree-repo-finder-mount.h" +#include "ostree-types.h" +#include "test-mock-gio.h" + +static void +result_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + GAsyncResult **result_out = user_data; + *result_out = g_object_ref (result); +} + +static void +collection_ref_free0 (OstreeCollectionRef *ref) +{ + g_clear_pointer (&ref, (GDestroyNotify) ostree_collection_ref_free); +} + +int +main (int argc, char **argv) +{ + g_autoptr(GError) error = NULL; + + setlocale (LC_ALL, ""); + + if (argc < 5 || (argc % 2) != 1) + { + g_printerr ("Usage: %s REPO MOUNT-ROOT COLLECTION-ID REF-NAME [COLLECTION-ID REF-NAME …]\n", argv[0]); + return 1; + } + + g_autoptr(GMainContext) context = g_main_context_new (); + g_main_context_push_thread_default (context); + + g_autoptr(OstreeRepo) parent_repo = ostree_repo_open_at (AT_FDCWD, argv[1], NULL, &error); + g_assert_no_error (error); + + /* Set up a mock volume. */ + g_autoptr(GFile) mount_root = g_file_new_for_commandline_arg (argv[2]); + g_autoptr(GMount) mount = G_MOUNT (ostree_mock_mount_new ("mount", mount_root)); + + g_autoptr(GList) mounts = g_list_prepend (NULL, mount); + + g_autoptr(GVolumeMonitor) monitor = ostree_mock_volume_monitor_new (mounts, NULL); + g_autoptr(OstreeRepoFinderMount) finder = ostree_repo_finder_mount_new (monitor); + + /* Resolve the refs. */ + g_autoptr(GPtrArray) refs = g_ptr_array_new_with_free_func ((GDestroyNotify) collection_ref_free0); + + for (gsize i = 3; i < argc; i += 2) + { + const char *collection_id = argv[i]; + const char *ref_name = argv[i + 1]; + + g_ptr_array_add (refs, ostree_collection_ref_new (collection_id, ref_name)); + } + + g_ptr_array_add (refs, NULL); /* NULL terminator */ + + g_autoptr(GAsyncResult) result = NULL; + ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder), + (const OstreeCollectionRef * const *) refs->pdata, + parent_repo, NULL, result_cb, &result); + + while (result == NULL) + g_main_context_iteration (context, TRUE); + + g_autoptr(GPtrArray) results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder), + result, &error); + g_assert_no_error (error); + + /* Check that the results are correct: the invalid refs should have been + * ignored, and the valid results canonicalised and deduplicated. */ + for (gsize i = 0; i < results->len; i++) + { + const OstreeRepoFinderResult *result = g_ptr_array_index (results, i); + GHashTableIter iter; + OstreeCollectionRef *ref; + const gchar *checksum; + + g_hash_table_iter_init (&iter, result->ref_to_checksum); + + while (g_hash_table_iter_next (&iter, (gpointer *) &ref, (gpointer *) &checksum)) + g_print ("%" G_GSIZE_FORMAT " %s %s %s %s\n", + i, ostree_remote_get_name (result->remote), + ref->collection_id, ref->ref_name, + checksum); + } + + g_main_context_pop_thread_default (context); + + return 0; +} diff --git a/tests/test-admin-deploy-2.sh b/tests/test-admin-deploy-2.sh new file mode 100755 index 0000000..0fa2df9 --- /dev/null +++ b/tests/test-admin-deploy-2.sh @@ -0,0 +1,124 @@ +#!/bin/bash +# +# Copyright (C) 2011,2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..7" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +export rev +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +echo "ok deploy command" + +# Commit + upgrade twice, so that we'll rotate out the original deployment +bootcsum1=${bootcsum} +os_repository_new_commit +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +bootcsum2=${bootcsum} +os_repository_new_commit "1" +bootcsum3=${bootcsum} +${CMD_PREFIX} ostree admin upgrade --os=testos + +newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +assert_not_streq ${rev} ${newrev} +assert_not_streq ${bootcsum1} ${bootcsum2} +assert_not_streq ${bootcsum2} ${bootcsum3} +assert_not_has_dir sysroot/boot/ostree/testos-${bootcsum1} +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} +assert_has_dir sysroot/boot/ostree/testos-${bootcsum2} +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS' + +echo "ok deploy and GC /boot" + +${CMD_PREFIX} ostree admin cleanup +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS' + +echo "ok manual cleanup" + +# Commit + upgrade twice, so that we'll rotate out the original deployment +os_repository_new_commit "1" +${CMD_PREFIX} ostree admin upgrade --os=testos +oldversion=${version} +# another commit with *same* bootcsum but *new* content +os_repository_new_commit "1" "2" +newversion=${version} +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf ${oldversion} +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf ${newversion} + +echo "ok new version same bootcsum" + +assert_n_pinned() { + local n=$1 + ${CMD_PREFIX} ostree admin status > status.txt + local n_pinned="$(grep -F -c -e 'Pinned: yes' < status.txt)" + if test "${n_pinned}" '!=' "${n}"; then + cat status.txt + fatal "${n_pinned} != ${n}" + fi +} +assert_n_deployments() { + local n=$1 + ${CMD_PREFIX} ostree admin status > status.txt + local n_deployments="$(grep -F -c -e 'Version: ' < status.txt)" + if test "${n_deployments}" '!=' "${n}"; then + cat status.txt + fatal "${n_deployments} != ${n}" + fi +} +assert_n_pinned 0 +${CMD_PREFIX} ostree admin pin 0 +assert_n_pinned 1 +${CMD_PREFIX} ostree admin pin -u 0 +assert_n_pinned 0 +echo "ok pin unpin" + +${CMD_PREFIX} ostree admin pin 0 1 +assert_n_pinned 2 +assert_n_deployments 2 +os_repository_new_commit +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_n_pinned 2 +assert_n_deployments 3 +echo "ok pin across upgrades" + +${CMD_PREFIX} ostree admin pin -u 1 +os_repository_new_commit +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_n_pinned 1 +assert_n_deployments 3 +os_repository_new_commit +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_n_pinned 1 +assert_n_deployments 3 + +echo "ok pinning" diff --git a/tests/test-admin-deploy-bootid-gc.sh b/tests/test-admin-deploy-bootid-gc.sh new file mode 100755 index 0000000..9a5094c --- /dev/null +++ b/tests/test-admin-deploy-bootid-gc.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Copyright (C) 2016 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..1" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +export rev +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +os_repository_new_commit + +rm sysroot/ostree/repo/tmp/* -rf +export TEST_BOOTID=4072029c-8b10-60d1-d31b-8422eeff9b42 +if env OSTREE_REPO_TEST_ERROR=pre-commit OSTREE_BOOTID=${TEST_BOOTID} \ + ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime 2>err.txt; then + assert_not_reached "Should have hit OSTREE_REPO_TEST_ERROR_PRE_COMMIT" +fi +stagepath=$(ls -d sysroot/ostree/repo/tmp/staging-${TEST_BOOTID}-*) +assert_has_dir "${stagepath}" + +# We have an older failed stage, now use a new boot id + +export NEW_TEST_BOOTID=5072029c-8b10-60d1-d31b-8422eeff9b42 +if env OSTREE_REPO_TEST_ERROR=pre-commit OSTREE_BOOTID=${NEW_TEST_BOOTID} \ + ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=FOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime 2>err.txt; then + assert_not_reached "Should have hit OSTREE_REPO_TEST_ERROR_PRE_COMMIT" +fi +newstagepath=$(ls -d sysroot/ostree/repo/tmp/staging-${NEW_TEST_BOOTID}-*) +assert_has_dir "${newstagepath}" +env OSTREE_BOOTID=${NEW_TEST_BOOTID} ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +newstagepath=$(echo sysroot/ostree/repo/tmp/staging-${NEW_TEST_BOOTID}-*) +assert_not_has_dir "${stagepath}" +assert_not_has_dir "${newstagepath}" + +echo "ok admin bootid GC" diff --git a/tests/test-admin-deploy-clean.sh b/tests/test-admin-deploy-clean.sh new file mode 100755 index 0000000..bca4525 --- /dev/null +++ b/tests/test-admin-deploy-clean.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# +# Copyright (C) 2015 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..1" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +export rev +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin undeploy 0 +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo refs > refs.txt +assert_not_file_has_content refs.txt '^ostree/' + +echo "ok deploy + undeploy repo prune" diff --git a/tests/test-admin-deploy-etcmerge-cornercases.sh b/tests/test-admin-deploy-etcmerge-cornercases.sh new file mode 100755 index 0000000..fab50d1 --- /dev/null +++ b/tests/test-admin-deploy-etcmerge-cornercases.sh @@ -0,0 +1,144 @@ +#!/bin/bash +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..2" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +export rev +echo "rev=${rev}" +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +etc=sysroot/ostree/deploy/testos/deploy/${rev}.0/etc + +# modified config file +echo "a modified config file" > ${etc}/NetworkManager/nm.conf + +# Ok, let's create a long directory chain with custom permissions +mkdir -p ${etc}/a/long/dir/chain +mkdir -p ${etc}/a/long/dir/forking +chmod 700 ${etc}/a +chmod 770 ${etc}/a/long +chmod 777 ${etc}/a/long/dir +chmod 707 ${etc}/a/long/dir/chain +chmod 700 ${etc}/a/long/dir/forking + +# Symlink to nonexistent path, to ensure we aren't walking symlinks +ln -s no-such-file ${etc}/a/link-to-no-such-file + +# Remove a directory +rm ${etc}/testdirectory -rf + +# Now deploy a new commit +os_repository_new_commit +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +echo "newrev=${newrev}" +newroot=sysroot/ostree/deploy/testos/deploy/${newrev}.0 +newetc=${newroot}/etc + +assert_file_has_content ${newroot}/usr/etc/NetworkManager/nm.conf "a default daemon file" +assert_file_has_content ${newetc}/NetworkManager/nm.conf "a modified config file" + +assert_file_has_mode() { + stat -c '%a' $1 > mode.txt + if ! grep -q -e "$2" mode.txt; then + echo 1>&2 "file $1 has mode $(cat mode.txt); expected $2"; + exit 1 + fi + rm -f mode.txt +} + +assert_file_has_mode ${newetc}/a 700 +assert_file_has_mode ${newetc}/a/long 770 +assert_file_has_mode ${newetc}/a/long/dir 777 +assert_file_has_mode ${newetc}/a/long/dir/chain 707 +assert_file_has_mode ${newetc}/a/long/dir/forking 700 +assert_file_has_mode ${newetc}/a/long/dir 777 + +test -L ${newetc}/a/link-to-no-such-file || assert_not_reached "should have symlink" + +assert_has_dir ${newroot}/usr/etc/testdirectory +assert_not_has_dir ${newetc}/testdirectory + +echo "ok" + +# Add /etc/initially-empty +cd "${test_tmpdir}/osdata" +mkdir -p usr/etc/initially-empty +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit -b testos/buildmaster/x86_64-runtime -s "Add empty directory" +cd ${test_tmpdir} + +# Upgrade, check that we have it +${CMD_PREFIX} ostree admin upgrade --os=testos +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +assert_has_dir sysroot/ostree/deploy/testos/deploy/$rev.0/etc/initially-empty + +# Now add a two files in initially-empty +cd "${test_tmpdir}/osdata" +touch usr/etc/initially-empty/{afile,bfile} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit -b testos/buildmaster/x86_64-runtime -s "Add empty directory" + +# Upgrade, check that we have the two new files +cd ${test_tmpdir} +${CMD_PREFIX} ostree admin upgrade --os=testos +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +assert_has_file sysroot/ostree/deploy/testos/deploy/$rev.0/etc/initially-empty/afile +assert_has_file sysroot/ostree/deploy/testos/deploy/$rev.0/etc/initially-empty/bfile + +# Replace config file with default directory +cd "${test_tmpdir}/osdata" +mkdir usr/etc/somenewdir +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit -b testos/buildmaster/x86_64-runtime -s "Add default dir" +cd ${test_tmpdir} +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +newconfpath=sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/somenewdir +echo "some content blah" > ${newconfpath} +if ${CMD_PREFIX} ostree admin upgrade --os=testos 2>err.txt; then + assert_not_reached "upgrade should have failed" +fi +assert_file_has_content err.txt "Modified config file newly defaults to directory" +rm ${newconfpath} + +# Remove parent directory of modified config file +cd "${test_tmpdir}/osdata" +rm -rf usr/etc/initially-empty +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit -b testos/buildmaster/x86_64-runtime -s "Remove default dir" +cd ${test_tmpdir} +newconfpath=sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/initially-empty/mynewfile +touch ${newconfpath} +${CMD_PREFIX} ostree admin upgrade --os=testos +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.0/usr/etc/initially-empty +assert_has_file sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/initially-empty/mynewfile +rm ${newconfpath} + +echo "ok" diff --git a/tests/test-admin-deploy-grub2.sh b/tests/test-admin-deploy-grub2.sh new file mode 100755 index 0000000..231aa2f --- /dev/null +++ b/tests/test-admin-deploy-grub2.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "grub2 ostree-grub-generator" + +extra_admin_tests=0 + +. $(dirname $0)/admin-test.sh diff --git a/tests/test-admin-deploy-karg.sh b/tests/test-admin-deploy-karg.sh new file mode 100755 index 0000000..ccf66b0 --- /dev/null +++ b/tests/test-admin-deploy-karg.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..3" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +export rev +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin deploy --karg=FOO=BAR --os=testos testos:testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin deploy --karg=TESTARG=TESTVALUE --os=testos testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=BAR' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*FOO=BAR' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*TESTARG=TESTVALUE' +${CMD_PREFIX} ostree admin deploy --karg=ANOTHERARG=ANOTHERVALUE --os=testos testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*TESTARG=TESTVALUE' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*ANOTHERARG=ANOTHERVALUE' + +echo "ok deploy with --karg, but same config" + +${CMD_PREFIX} ostree admin deploy --karg-proc-cmdline --os=testos testos:testos/buildmaster/x86_64-runtime +for arg in $(cat /proc/cmdline); do + case "$arg" in + ostree=*) # Skip ostree arg that gets stripped out + ;; + initrd=*|BOOT_IMAGE=*) # Skip options set by bootloader that gets filtered out + ;; + *) assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf "options.*$arg" + ;; + esac +done + +echo "ok deploy --karg-proc-cmdline" + +${CMD_PREFIX} ostree admin status +${CMD_PREFIX} ostree admin undeploy 0 + +${CMD_PREFIX} ostree admin deploy --os=testos --karg-append=APPENDARG=VALAPPEND --karg-append=APPENDARG=2NDAPPEND testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*FOO=BAR' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*TESTARG=TESTVALUE' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*APPENDARG=VALAPPEND .*APPENDARG=2NDAPPEND' + +# Check correct ordering of different-valued args of the same key. +${CMD_PREFIX} ostree admin deploy --os=testos --karg-append=FOO=TESTORDERED --karg-append=APPENDARG=3RDAPPEND testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'options.*APPENDARG=VALAPPEND .*APPENDARG=2NDAPPEND .*FOO=TESTORDERED .*APPENDARG=3RDAPPEND' + +echo "ok deploy --karg-append" diff --git a/tests/test-admin-deploy-nomerge.sh b/tests/test-admin-deploy-nomerge.sh new file mode 100755 index 0000000..0627142 --- /dev/null +++ b/tests/test-admin-deploy-nomerge.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Copyright (C) 2020 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime + +echo "1..1" +${CMD_PREFIX} ostree admin deploy --os=testos --karg=root=LABEL=foo --karg=testkarg=1 testos:testos/buildmaster/x86_64-runtime +origdeployment=$(${CMD_PREFIX} ostree admin --sysroot=sysroot --print-current-dir) +testconfig=etc/modified-config-file-that-will-be-removed +touch "${origdeployment}"/"${testconfig}" +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf "^options.*root=LABEL=foo.*testkarg" +${CMD_PREFIX} ostree admin deploy --os=testos --no-merge --karg=root=LABEL=bar testos:testos/buildmaster/x86_64-runtime +deployment=$(${CMD_PREFIX} ostree admin --sysroot=sysroot --print-current-dir) +assert_not_streq "${origdeployment}" "${deployment}" +assert_not_has_file "${deployment}/${testconfig}" +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf "^options root=LABEL=bar" +assert_not_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf "^options .*testkarg" +echo "ok no merge deployment" diff --git a/tests/test-admin-deploy-none.sh b/tests/test-admin-deploy-none.sh new file mode 100755 index 0000000..09dee62 --- /dev/null +++ b/tests/test-admin-deploy-none.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# +# Copyright (C) 2019 Robert Fairley +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "sysroot.bootloader none" + +extra_admin_tests=1 + +. $(dirname $0)/admin-test.sh + +# Test that the bootloader configuration "none" generates BLS config snippets. +cd ${test_tmpdir} +rm httpd osdata testos-repo sysroot -rf +setup_os_repository "archive" "sysroot.bootloader none" +${CMD_PREFIX} ostree pull-local --repo=sysroot/ostree/repo --remote testos testos-repo testos/buildmaster/x86_64-runtime +# Test that configuring sysroot.bootloader="none" is a workaround for previous +# grub2 bootloader issue (see https://github.com/ostreedev/ostree/issues/1774) +mkdir -p sysroot/boot/grub2 +touch sysroot/boot/grub2/grub.cfg +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os testos testos/buildmaster/x86_64-runtime > out.txt +assert_file_has_content out.txt "Bootloader updated.*" +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.* root=LABEL=MOO' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/.vmlinuz-3.6.0.hmac 'an hmac file' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' +echo "ok generate bls config on first deployment" + +# TODO: add tests to try setting with an unsupported bootloader config, +# once https://github.com/ostreedev/ostree/issues/1827 is solved. +# The tests should check that the following commands fail: +# ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set sysroot.bootloader unsupported_bootloader +# ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set sysroot.bootloader "" diff --git a/tests/test-admin-deploy-switch.sh b/tests/test-admin-deploy-switch.sh new file mode 100755 index 0000000..bae6766 --- /dev/null +++ b/tests/test-admin-deploy-switch.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..4" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos:testos/buildmaster/x86_64-runtime) +assert_not_has_file sysroot/ostree/deploy/testos/deploy/$newrev.0/usr/include/foo.h +if ${CMD_PREFIX} ostree admin switch --os=testos testos/buildmaster/x86_64-runtime; then + assert_not_reached "Switch to same ref unexpectedly succeeded" +fi +echo "ok switch expected error" + +${CMD_PREFIX} ostree admin switch --os=testos testos/buildmaster/x86_64-devel +newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos:testos/buildmaster/x86_64-devel) +assert_file_has_content sysroot/ostree/deploy/testos/deploy/$newrev.0/usr/include/foo.h 'header' + +echo "ok switch" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false anothertestos file://$(pwd)/testos-repo +${CMD_PREFIX} ostree admin switch --os=testos anothertestos:testos/buildmaster/x86_64-devel +# Ok this is lame, need a better shell command to extract config, or switch to gjs +${CMD_PREFIX} ostree admin status > status.txt +assert_file_has_content status.txt anothertestos + +echo "ok switch remotes" + +${CMD_PREFIX} ostree admin switch --os=testos testos: + +echo "ok switch remote only" diff --git a/tests/test-admin-deploy-syslinux.sh b/tests/test-admin-deploy-syslinux.sh new file mode 100755 index 0000000..4d4ac7a --- /dev/null +++ b/tests/test-admin-deploy-syslinux.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# +# Copyright (C) 2011,2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +extra_admin_tests=3 + +. $(dirname $0)/admin-test.sh + +# Test the legacy dirs +for test_bootdir in "boot" "usr/lib/ostree-boot"; do + cd ${test_tmpdir} + rm httpd osdata testos-repo sysroot -rf + setup_os_repository "archive" "syslinux" $test_bootdir + ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime + rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) + ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime + assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.* root=LABEL=MOO' + assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.* quiet' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' + # kernel/initrams should also be in the tree's /boot with the checksum + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/vmlinuz-3.6.0-${bootcsum} 'a kernel' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/initramfs-3.6.0.img-${bootcsum} 'an initramfs' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' + assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' + ${CMD_PREFIX} ostree admin status + validate_bootloader + echo "ok kernel in $test_bootdir" +done + +# And test that legacy overrides /usr/lib/modules +cd ${test_tmpdir} +rm httpd osdata testos-repo sysroot -rf +setup_os_repository "archive" "syslinux" "usr/lib/ostree-boot" +cd osdata +echo "this is a kernel without an initramfs like Fedora 26" > usr/lib/modules/3.6.0/vmlinuz +usrlib_modules_bootcsum=$(cat usr/lib/modules/3.6.0/vmlinuz | sha256sum | cut -f 1 -d ' ') +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build" +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.* root=LABEL=MOO' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' +# Note this bootcsum shouldn't be the modules one +assert_not_streq "${bootcsum}" "${usrlib_modules_bootcsum}" +echo "ok kernel in /usr/lib/modules and /usr/lib/ostree-boot" diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh new file mode 100755 index 0000000..e3163cb --- /dev/null +++ b/tests/test-admin-deploy-uboot.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# +# Copyright (C) 2011,2014 Colin Walters +# Copyright (C) 2013 Javier Martinez +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +kver="3.6.0" +modulesdir="usr/lib/modules/${kver}" +setup_os_repository "archive" "uboot" ${modulesdir} + +extra_admin_tests=2 + +. $(dirname $0)/admin-test.sh + +cd ${test_tmpdir} +# Note this test actually requires a checksum change to /boot, +# because adding the uEnv.txt isn't currently covered by the +# "bootcsum". +os_repository_new_commit "uboot test" "test upgrade multiple kernel args" +mkdir -p osdata/usr/lib/ostree-boot +cat << 'EOF' > osdata/usr/lib/ostree-boot/uEnv.txt +loaduimage=load mmc ${bootpart} ${loadaddr} ${kernel_image} +loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}${fdtfile} +loadramdisk=load mmc ${bootpart} ${rdaddr} ${ramdisk_image} +mmcargs=setenv bootargs $bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype} +mmcboot=run loadramdisk; echo Booting from mmc ....; run mmcargs; bootz ${loadaddr} ${rdaddr} ${fdtaddr} +EOF +${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_file_has_content sysroot/boot/uEnv.txt "loadfdt=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image2=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image3=" + +echo "ok merging uEnv.txt files" + +cd ${test_tmpdir} +os_repository_new_commit "uboot test" "test with device tree directory" + +devicetree_path=osdata/${modulesdir}/dtb/asoc-board.dtb +devicetree_overlay_path=osdata/${modulesdir}/dtb/overlays/overlay.dtbo + +mkdir -p osdata/${modulesdir}/dtb +echo "a device tree" > ${devicetree_path} +mkdir -p osdata/${modulesdir}/dtb/overlays +echo "a device tree overlay" > ${devicetree_overlay_path} + +bootcsum=$( + (echo "new: a kernel uboot test" && echo "new: an initramfs uboot test" && + cat ${devicetree_path} ${devicetree_overlay_path} ) | + sha256sum | cut -f 1 -d ' ') + +${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin upgrade --os=testos +assert_file_has_content sysroot/boot/uEnv.txt "fdtdir=" +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/dtb/asoc-board.dtb 'a device tree' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/dtb/overlays/overlay.dtbo 'a device tree overlay' + +echo "ok deploying fdtdir" diff --git a/tests/test-admin-gpg.sh b/tests/test-admin-gpg.sh new file mode 100755 index 0000000..dc77674 --- /dev/null +++ b/tests/test-admin-gpg.sh @@ -0,0 +1,151 @@ +#!/bin/bash +# +# Copyright (C) 2019 Rafael Fonseca +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_os_repository_signed () { + mode=$1 + shift + bootmode=$1 + shift + bootdir=${1:-usr/lib/modules/3.6.0} + + oldpwd=`pwd` + keyid="472CDAFA" + + cd ${test_tmpdir} + mkdir testos-repo + if test -n "$mode"; then + ostree_repo_init testos-repo --mode=${mode} + else + ostree_repo_init testos-repo + fi + + cd ${test_tmpdir} + mkdir osdata + cd osdata + kver=3.6.0 + mkdir -p usr/bin ${bootdir} usr/lib/modules/${kver} usr/share usr/etc + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs.img + # /usr/lib/modules just uses "vmlinuz", since the version is in the module + # directory name. + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-${kver} + initramfs_path=${bootdir}/initramfs-${kver}.img + fi + echo "a kernel" > ${kernel_path} + echo "an initramfs" > ${initramfs_path} + bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ') + export bootcsum + # Add the checksum for legacy dirs (/boot, /usr/lib/ostree-boot), but not + # /usr/lib/modules. + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} + fi + + echo "an executable" > usr/bin/sh + echo "some shared data" > usr/share/langs.txt + echo "a library" > usr/lib/libfoo.so.0 + ln -s usr/bin bin +cat > usr/etc/os-release < usr/etc/aconfigfile + mkdir -p usr/etc/NetworkManager + echo "a default daemon file" > usr/etc/NetworkManager/nm.conf + mkdir -p usr/etc/testdirectory + echo "a default daemon file" > usr/etc/testdirectory/test + + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build" --gpg-sign=$keyid --gpg-homedir=${test_tmpdir}/gpghome + + # Ensure these commits have distinct second timestamps + sleep 2 + echo "a new executable" > usr/bin/sh + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.10 -b testos/buildmaster/x86_64-runtime -s "Build" --gpg-sign=$keyid --gpg-homedir=${test_tmpdir}/gpghome + + cd ${test_tmpdir} + rm -rf osdata-devel + mkdir osdata-devel + tar -C osdata -cf - . | tar -C osdata-devel -xf - + cd osdata-devel + mkdir -p usr/include + echo "a development header" > usr/include/foo.h + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-devel -s "Build" --gpg-sign=$keyid --gpg-homedir=${test_tmpdir}/gpghome + + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo fsck -q + + cd ${test_tmpdir} + mkdir sysroot + export OSTREE_SYSROOT=sysroot + ${CMD_PREFIX} ostree admin init-fs sysroot + if test -n "${OSTREE_NO_XATTRS:-}"; then + echo -e 'disable-xattrs=true\n' >> sysroot/ostree/repo/config + fi + ${CMD_PREFIX} ostree admin os-init testos + + case $bootmode in + "syslinux") + setup_os_boot_syslinux + ;; + "uboot") + setup_os_boot_uboot + ;; + *grub2*) + setup_os_boot_grub2 "${bootmode}" + ;; + esac + + cd ${test_tmpdir} + mkdir ${test_tmpdir}/httpd + cd httpd + ln -s ${test_tmpdir} ostree + ${OSTREE_HTTPD} --autoexit --daemonize -p ${test_tmpdir}/httpd-port + port=$(cat ${test_tmpdir}/httpd-port) + echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address + cd ${oldpwd} +} + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository_signed "archive" "syslinux" + +echo "1..2" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add testos $(cat httpd-address)/ostree/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --gpg-verify=true --remote=testos testos-repo testos/buildmaster/x86_64-runtime +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +echo "ok deploy command" + +${CMD_PREFIX} ostree admin status > status.txt +test -f status.txt +assert_file_has_content status.txt "GPG: Signature made" +assert_not_file_has_content status.txt "GPG: Can't check signature: public key not found" +echo 'ok gpg signature' diff --git a/tests/test-admin-instutil-set-kargs.sh b/tests/test-admin-instutil-set-kargs.sh new file mode 100755 index 0000000..1cb3218 --- /dev/null +++ b/tests/test-admin-instutil-set-kargs.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# Copyright (C) 2014 Owen Taylor +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..5" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime + +${CMD_PREFIX} ostree admin instutil set-kargs FOO=BAR +${CMD_PREFIX} ostree admin instutil set-kargs FOO=BAZ FOO=BIF TESTARG=TESTVALUE KEYWORD EMPTYLIST= +assert_not_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=BAR' +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=BAZ .*FOO=BIF' +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*TESTARG=TESTVALUE KEYWORD EMPTYLIST=' +echo "ok instutil set-kargs (basic)" + +${CMD_PREFIX} ostree admin instutil set-kargs --merge FOO=BAR +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=BAZ .*FOO=BIF .*FOO=BAR' +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*TESTARG=TESTVALUE KEYWORD EMPTYLIST=' +echo "ok instutil set-kargs --merge" + +${CMD_PREFIX} ostree admin instutil set-kargs --merge --replace=FOO=XXX +assert_not_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=BAR' +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=XXX' +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*TESTARG=TESTVALUE KEYWORD EMPTYLIST=' +echo "ok instutil set-kargs --replace" + +${CMD_PREFIX} ostree admin instutil set-kargs --merge --append=FOO=BAR --append=APPENDARG=VALAPPEND --append=APPENDARG=2NDAPPEND testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*FOO=XXX.*FOO=BAR' +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'options.*APPENDARG=VALAPPEND .*APPENDARG=2NDAPPEND' +echo "ok instutil set-kargs --append" + +${CMD_PREFIX} ostree admin instutil set-kargs --import-proc-cmdline +for arg in $(cat /proc/cmdline); do + case "$arg" in + ostree=*) # Skip ostree arg that gets stripped out + ;; + initrd=*|BOOT_IMAGE=*) # Skip options set by bootloader that gets filtered out + ;; + *) assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf "options.*$arg" + ;; + esac +done +echo "ok instutil set-kargs --import-proc-cmdline" diff --git a/tests/test-admin-locking.sh b/tests/test-admin-locking.sh new file mode 100755 index 0000000..7e70850 --- /dev/null +++ b/tests/test-admin-locking.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# +# Copyright (C) 2015 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +# If parallel is not installed, skip the test +if ! parallel --gnu /bin/true /dev/null 2>&1; then + echo "1..0 # SKIP GNU parallel not available" + exit 0 +fi + +echo "1..1" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +export rev +echo "rev=${rev}" +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +parallel_cmd="parallel --gnu" +if parallel --help | grep -q -e --no-notice; then + parallel_cmd="${parallel_cmd} --no-notice" +fi + +count=$(($(getconf _NPROCESSORS_ONLN) * 2)) +seq "${count}" | ${parallel_cmd} -n0 ${CMD_PREFIX} ostree admin deploy --retain --os=testos testos:testos/buildmaster/x86_64-runtime + +${CMD_PREFIX} ostree admin status > status.txt +grep "testos ${rev}" status.txt | wc -l > status-matches.txt +assert_file_has_content status-matches.txt $((${count} + 1)) + +echo 'ok deploy locking' diff --git a/tests/test-admin-pull-deploy-commit.sh b/tests/test-admin-pull-deploy-commit.sh new file mode 100755 index 0000000..557ae60 --- /dev/null +++ b/tests/test-admin-pull-deploy-commit.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# +# Copyright (C) 2015 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# See https://github.com/GNOME/ostree/pull/145 + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..1" + +setup_os_repository "archive" "syslinux" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +parent_rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse ${rev}^) +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos ${parent_rev} +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos ${parent_rev} + +echo 'ok deploy pulled commit' diff --git a/tests/test-admin-pull-deploy-split.sh b/tests/test-admin-pull-deploy-split.sh new file mode 100755 index 0000000..1196368 --- /dev/null +++ b/tests/test-admin-pull-deploy-split.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Copyright (C) 2017 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# See https://github.com/ostreedev/ostree/pull/642 + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..1" + +setup_os_repository "archive" "syslinux" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +parent_rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse ${rev}^) +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime@${parent_rev} +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/ostree/deploy/testos/deploy/${parent_rev}.0 +assert_not_has_dir sysroot/ostree/deploy/testos/deploy/${rev}.0 +# Do a pull, this one should get us new content +${CMD_PREFIX} ostree admin upgrade --os=testos --pull-only --os=testos > out.txt +assert_not_file_has_content out.txt 'No update available' +# And pull again should still tell us we have new content +${CMD_PREFIX} ostree admin upgrade --os=testos --pull-only --os=testos > out.txt +assert_not_file_has_content out.txt 'No update available' +assert_has_dir sysroot/ostree/deploy/testos/deploy/${parent_rev}.0 +assert_not_has_dir sysroot/ostree/deploy/testos/deploy/${rev}.0 +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'TestOS 42 1\.0\.9' +assert_streq "${rev}" $(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +# Now, generate new content upstream; we shouldn't pull it +os_repository_new_commit +${CMD_PREFIX} ostree admin upgrade --os=testos --deploy-only --os=testos > out.txt +assert_not_file_has_content out.txt 'No update available' +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'TestOS 42 1\.0\.10' +assert_has_dir sysroot/ostree/deploy/testos/deploy/${parent_rev}.0 +assert_has_dir sysroot/ostree/deploy/testos/deploy/${rev}.0 +${CMD_PREFIX} ostree admin upgrade --os=testos --deploy-only --os=testos > out.txt +assert_file_has_content out.txt 'No update available' + +echo 'ok upgrade --pull-only + --deploy-only' diff --git a/tests/test-admin-upgrade-endoflife.sh b/tests/test-admin-upgrade-endoflife.sh new file mode 100755 index 0000000..8a0dc9c --- /dev/null +++ b/tests/test-admin-upgrade-endoflife.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" +# This does: +# - init ostree repo in testos-repo +# - create system files in osdata and commit twice those contents into testos-repo +# - copy osdata to osdata-devel and make another change then commit +# - create sysroot with init-fs and os-init and syslinux +# sysroot has /ostree basics (but no contents), syslinux cfg and empty root dirs + +echo "1..3" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +echo "rev=${rev}" + +# Now sysroot/ostree has the objects from the testos-repo (obtained over http +# and kept in remote "testos"), but there is no deployment + +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +echo "ok deploy" + +# Create a new branch which we want to migrate to +os_repository_new_commit 1 1 testos/buildmaster/newbranch +# bootcsum now refers to this new commit + +# Create a new commit with an empty tree, which marks the original branch as +# EOL, redirecting to the new one. +mkdir empty +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --tree=dir=$(pwd)/empty --add-metadata-string "ostree.endoflife=Product discontinued" --add-metadata-string "ostree.endoflife-rebase=testos/buildmaster/newbranch" -b testos/buildmaster/x86_64-runtime -s "EOL redirect to new branch" + +echo "ok new branch" + +# Upgrade existing checkout +${CMD_PREFIX} ostree admin upgrade --os=testos --pull-only +${CMD_PREFIX} ostree admin upgrade --os=testos --deploy-only + +# Check we got redirected to the new branch +assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf "${bootcsum}" +rev=$(${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo rev-parse testos/buildmaster/newbranch) +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/usr/bin/content-iteration "1" + +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0.origin "newbranch" + +echo "ok update and redirect" diff --git a/tests/test-admin-upgrade-not-backwards.sh b/tests/test-admin-upgrade-not-backwards.sh new file mode 100755 index 0000000..c23dbf2 --- /dev/null +++ b/tests/test-admin-upgrade-not-backwards.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..2" + +ref=testos/buildmaster/x86_64-runtime +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos ${ref} +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse ${ref}) +export rev +echo "rev=${rev}" +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:${ref} +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +# This should be a no-op +${CMD_PREFIX} ostree admin upgrade --os=testos + +# Generate a new commit with an older timestamp that also has +# some new content, so we test timestamp checking during pull +# +origrev=$(ostree --repo=${test_tmpdir}/sysroot/ostree/repo rev-parse testos:${ref}) +cd ${test_tmpdir}/osdata +echo "new content for pull timestamp checking" > usr/share/test-pull-ts-check.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string "version=tscheck" \ + -b ${ref} --timestamp='October 25 1985' +newrev=$(ostree --repo=${test_tmpdir}/testos-repo rev-parse ${ref}) +assert_not_streq ${origrev} ${newrev} +cd ${test_tmpdir} +tscheck_checksum=$(ostree_file_path_to_checksum testos-repo ${ref} /usr/share/test-pull-ts-check.txt) +tscheck_filez_objpath=$(ostree_checksum_to_relative_object_path testos-repo ${tscheck_checksum}) +assert_has_file testos-repo/${tscheck_filez_objpath} +if ${CMD_PREFIX} ostree admin upgrade --os=testos 2>upgrade-err.txt; then + assert_not_reached 'upgrade unexpectedly succeeded' +fi +assert_file_has_content upgrade-err.txt 'chronologically older' +currev=$(ostree --repo=sysroot/ostree/repo rev-parse testos:${ref}) +assert_not_streq ${newrev} ${currev} +assert_streq ${origrev} ${currev} +tscheck_file_objpath=$(ostree_checksum_to_relative_object_path sysroot/ostree/repo ${tscheck_checksum}) +assert_not_has_file sysroot/ostree/repo/${tscheck_file_objpath} + +echo 'ok upgrade will not go backwards' + +${CMD_PREFIX} ostree admin upgrade --os=testos --allow-downgrade + +echo 'ok upgrade backwards' diff --git a/tests/test-admin-upgrade-systemd-update.sh b/tests/test-admin-upgrade-systemd-update.sh new file mode 100755 index 0000000..94b750d --- /dev/null +++ b/tests/test-admin-upgrade-systemd-update.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive-z2" "syslinux" + +echo "1..2" + +# Setup a deployment +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/ostree/deploy/testos/deploy/${rev}.0/usr +assert_has_dir sysroot/ostree/deploy/testos/deploy/${rev}.0/etc +assert_has_dir sysroot/ostree/deploy/testos/var +assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/.updated +assert_not_has_file sysroot/ostree/deploy/testos/var/.updated + +echo "ok deploy" + +# Create the /etc/.updated and /var/.updated files with /usr modification time +usr=sysroot/ostree/deploy/testos/deploy/${rev}.0/usr +touch -r ${usr} sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/.updated +touch -r ${usr} sysroot/ostree/deploy/testos/var/.updated + +# Make a new commit, upgrade and ensure .updated files are gone in the +# new deployment but /etc/.updated still exists in the previous +# (current) deployment +os_repository_new_commit +${CMD_PREFIX} ostree admin upgrade --os=testos +newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +assert_not_has_file sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/.updated +assert_not_has_file sysroot/ostree/deploy/testos/var/.updated +assert_has_file sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/.updated + +echo "ok .updated files removed" diff --git a/tests/test-admin-upgrade-unconfigured.sh b/tests/test-admin-upgrade-unconfigured.sh new file mode 100755 index 0000000..d9a15fc --- /dev/null +++ b/tests/test-admin-upgrade-unconfigured.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive" "syslinux" + +echo "1..2" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +export rev +echo "rev=${rev}" +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +echo "unconfigured-state=Use \"subscription-manager\" to enable online updates for example.com OS" >> sysroot/ostree/deploy/testos/deploy/${rev}.0.origin + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime +if ${CMD_PREFIX} ostree admin upgrade --os=testos 2>err.txt; then + assert_not_reached "upgrade unexpectedly succeeded" +fi +assert_file_has_content err.txt "Use.*subscription.*online" + +echo "ok error" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false otheros file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin switch --os=testos otheros:testos/buildmaster/x86_64-runtime + +echo "ok switch" diff --git a/tests/test-archivez.sh b/tests/test-archivez.sh new file mode 100755 index 0000000..c27ce03 --- /dev/null +++ b/tests/test-archivez.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..13' + +setup_test_repository "archive" + +. ${test_srcdir}/archive-test.sh + +${CMD_PREFIX} ostree --repo=repo-archive-z2 init --mode=archive-z2 +echo "ok did an init with archive-z2 alias" + +cd ${test_tmpdir} +mkdir repo2 +ostree_repo_init repo2 +${CMD_PREFIX} ostree --repo=repo2 remote add --set=gpg-verify=false aremote file://$(pwd)/repo test2 +${CMD_PREFIX} ostree --repo=repo2 pull aremote +${CMD_PREFIX} ostree --repo=repo2 rev-parse aremote/test2 +${CMD_PREFIX} ostree --repo=repo2 fsck +echo "ok pull with from file:/// uri" diff --git a/tests/test-auto-summary.sh b/tests/test-auto-summary.sh new file mode 100755 index 0000000..3a04f18 --- /dev/null +++ b/tests/test-auto-summary.sh @@ -0,0 +1,103 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# Copyright (C) 2015 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +echo "1..4" + +. $(dirname $0)/libtest.sh + +setup_test_repository "bare" +echo "ok setup" + +# Check that without commit-update-summary set, creating a commit doesn't update the summary +mkdir test + +echo hello > test/a + +$OSTREE commit -b test -s "A commit" test +echo "ok commit 1" + +$OSTREE summary --update + +OLD_MD5=$(md5sum repo/summary) + +echo hello2 > test/a + +$OSTREE commit -b test -s "Another commit" test +echo "ok commit 2" + +assert_streq "$OLD_MD5" "$(md5sum repo/summary)" + +# Check that with commit-update-summary set, creating a commit updates the summary +$OSTREE --repo=repo config set core.commit-update-summary true + +echo hello3 > test/a + +$OSTREE commit -b test -s "Another commit..." test +echo "ok commit 3" + +assert_not_streq "$OLD_MD5" "$(md5sum repo/summary)" + +$OSTREE --repo=repo config set core.commit-update-summary false + +# Check that summary --update deletes the .sig file +touch repo/summary.sig +$OSTREE summary --update +assert_not_has_file repo/summary.sig + +# Check that without auto-update-summary set, adding, changing, or deleting a ref doesn't update the summary +$OSTREE summary --update +OLD_MD5=$(md5sum repo/summary) +$OSTREE commit -b test2 -s "A commit" test + +assert_streq "$OLD_MD5" "$(md5sum repo/summary)" + +$OSTREE reset test test^ + +assert_streq "$OLD_MD5" "$(md5sum repo/summary)" + +$OSTREE refs --delete test + +assert_streq "$OLD_MD5" "$(md5sum repo/summary)" + +# Check that with auto-update-summary set, adding, changing, or deleting a ref updates the summary +$OSTREE --repo=repo config set core.auto-update-summary true + +$OSTREE summary --update +OLD_MD5=$(md5sum repo/summary) +echo hello > test/a +$OSTREE commit -b test -s "A commit" test +echo hello2 > test/a +$OSTREE commit -b test -s "Another commit" test + +assert_not_streq "$OLD_MD5" "$(md5sum repo/summary)" + +OLD_MD5=$(md5sum repo/summary) +$OSTREE reset test test^ + +assert_not_streq "$OLD_MD5" "$(md5sum repo/summary)" + +OLD_MD5=$(md5sum repo/summary) +$OSTREE refs --delete test + +assert_not_streq "$OLD_MD5" "$(md5sum repo/summary)" diff --git a/tests/test-basic-c.c b/tests/test-basic-c.c new file mode 100644 index 0000000..ff6d353 --- /dev/null +++ b/tests/test-basic-c.c @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "libglnx.h" +#include "libostreetest.h" + +static void +test_repo_is_not_system (gconstpointer data) +{ + OstreeRepo *repo = (void*)data; + g_assert (!ostree_repo_is_system (repo)); +} + +static GBytes * +input_stream_to_bytes (GInputStream *input) +{ + g_autoptr(GOutputStream) mem_out_stream = NULL; + g_autoptr(GError) error = NULL; + + if (input == NULL) + return g_bytes_new (NULL, 0); + + mem_out_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free); + g_output_stream_splice (mem_out_stream, + input, + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, + NULL, + &error); + g_assert_no_error (error); + + return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (mem_out_stream)); +} + +static void +test_raw_file_to_archive_stream (gconstpointer data) +{ + OstreeRepo *repo = OSTREE_REPO (data); + g_autofree gchar *commit_checksum = NULL; + g_autoptr(GHashTable) reachable = NULL; + g_autoptr(GError) error = NULL; + /* branch name of the test repository, see setup_test_repository in libtest.sh */ + const gchar *rev = "test2"; + GHashTableIter iter; + GVariant *serialized_object; + guint checks = 0; + + ostree_repo_resolve_rev (repo, + rev, + FALSE, + &commit_checksum, + &error); + g_assert_no_error (error); + ostree_repo_traverse_commit (repo, + commit_checksum, + -1, + &reachable, + NULL, + &error); + g_assert_no_error (error); + g_hash_table_iter_init (&iter, reachable); + while (g_hash_table_iter_next (&iter, (gpointer*)&serialized_object, NULL)) + { + const gchar *object_checksum; + OstreeObjectType object_type; + g_autoptr(GInputStream) input = NULL; + g_autoptr(GFileInfo) info = NULL; + g_autoptr(GVariant) xattrs = NULL; + g_autoptr(GBytes) input_bytes = NULL; + g_autoptr(GInputStream) mem_input = NULL; + g_autoptr(GInputStream) zlib_stream = NULL; + g_autoptr(GBytes) zlib_bytes = NULL; + g_autoptr(GInputStream) mem_zlib = NULL; + g_autoptr(GInputStream) input2 = NULL; + g_autoptr(GFileInfo) info2 = NULL; + g_autoptr(GVariant) xattrs2 = NULL; + g_autoptr(GBytes) input2_bytes = NULL; + + ostree_object_name_deserialize (serialized_object, &object_checksum, &object_type); + if (object_type != OSTREE_OBJECT_TYPE_FILE) + continue; + + ostree_repo_load_file (repo, + object_checksum, + &input, + &info, + &xattrs, + NULL, + &error); + g_assert_no_error (error); + + input_bytes = input_stream_to_bytes (input); + /* This is to simulate NULL input received from + * ostree_repo_load_file. Instead of creating the mem_input + * variable, I could also rewind the input stream and pass it to + * the function below, but this would assume that the input + * stream implements either the GSeekable or + * GFileDescriptorBased interface. */ + if (input != NULL) + mem_input = g_memory_input_stream_new_from_bytes (input_bytes); + ostree_raw_file_to_archive_z2_stream (mem_input, + info, + xattrs, + &zlib_stream, + NULL, + &error); + g_assert_no_error (error); + + zlib_bytes = input_stream_to_bytes (zlib_stream); + mem_zlib = g_memory_input_stream_new_from_bytes (zlib_bytes); + ostree_content_stream_parse (FALSE, + mem_zlib, + g_bytes_get_size (zlib_bytes), + FALSE, + &input2, + &info2, + &xattrs2, + NULL, + &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); + + g_seekable_seek (G_SEEKABLE (mem_zlib), + 0, + G_SEEK_SET, + NULL, + &error); + g_assert_no_error (error); + + ostree_content_stream_parse (TRUE, + mem_zlib, + g_bytes_get_size (zlib_bytes), + FALSE, + &input2, + &info2, + &xattrs2, + NULL, + &error); + g_assert_no_error (error); + + input2_bytes = input_stream_to_bytes (input2); + g_assert_true (g_bytes_equal (input_bytes, input2_bytes)); + g_assert_true (g_variant_equal (xattrs, xattrs2)); + /* TODO: Not sure how to compare fileinfos */ + ++checks; + } + /* to make sure we really tested the function */ + g_assert_cmpint (checks, >, 0); +} + +static gboolean hi_content_stream_new (GInputStream **out_stream, + guint64 *out_length, + GError **error) +{ + static const char hi[] = "hi"; + g_autoptr(GMemoryInputStream) hi_memstream = (GMemoryInputStream*)g_memory_input_stream_new_from_data (hi, sizeof(hi)-1, NULL); + g_autoptr(GFileInfo) finfo = g_file_info_new (); + g_file_info_set_attribute_uint32 (finfo, "standard::type", G_FILE_TYPE_REGULAR); + g_file_info_set_attribute_boolean (finfo, "standard::is-symlink", FALSE); + g_file_info_set_attribute_uint32 (finfo, "unix::uid", 0); + g_file_info_set_attribute_uint32 (finfo, "unix::gid", 0); + g_file_info_set_attribute_uint32 (finfo, "unix::mode", S_IFREG|0644); + return ostree_raw_file_to_content_stream ((GInputStream*)hi_memstream, finfo, NULL, out_stream, out_length, NULL, error); +} + +static void +test_validate_remotename (void) +{ + const char *valid[] = {"foo", "hello-world"}; + const char *invalid[] = {"foo/bar", ""}; + for (guint i = 0; i < G_N_ELEMENTS(valid); i++) + { + g_autoptr(GError) error = NULL; + g_assert (ostree_validate_remote_name (valid[i], &error)); + g_assert_no_error (error); + } + for (guint i = 0; i < G_N_ELEMENTS(invalid); i++) + { + g_autoptr(GError) error = NULL; + g_assert (!ostree_validate_remote_name (invalid[i], &error)); + g_assert (error != NULL); + } +} + +static void +test_object_writes (gconstpointer data) +{ + OstreeRepo *repo = OSTREE_REPO (data); + g_autoptr(GError) error = NULL; + + static const char hi_sha256[] = "2301b5923720c3edc1f0467addb5c287fd5559e3e0cd1396e7f1edb6b01be9f0"; + + /* Successful content write */ + { g_autoptr(GInputStream) hi_memstream = NULL; + guint64 len; + hi_content_stream_new (&hi_memstream, &len, &error); + g_assert_no_error (error); + g_autofree guchar *csum = NULL; + (void)ostree_repo_write_content (repo, hi_sha256, hi_memstream, len, &csum, + NULL, &error); + g_assert_no_error (error); + } + + /* Invalid content write */ + { g_autoptr(GInputStream) hi_memstream = NULL; + guint64 len; + hi_content_stream_new (&hi_memstream, &len, &error); + g_assert_no_error (error); + g_autofree guchar *csum = NULL; + static const char invalid_hi_sha256[] = "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe"; + g_assert (!ostree_repo_write_content (repo, invalid_hi_sha256, hi_memstream, len, &csum, + NULL, &error)); + g_assert (error); + g_assert (strstr (error->message, "Corrupted file object")); + } +} + +static gboolean +impl_test_break_hardlink (int tmp_dfd, + const char *path, + GError **error) +{ + const char *linkedpath = glnx_strjoina (path, ".link"); + struct stat orig_stbuf; + if (!glnx_fstatat (tmp_dfd, path, &orig_stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + /* Calling ostree_break_hardlink() should be a noop */ + struct stat stbuf; + if (!ostree_break_hardlink (tmp_dfd, path, TRUE, NULL, error)) + return FALSE; + if (!glnx_fstatat (tmp_dfd, path, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + + g_assert_cmpint (orig_stbuf.st_dev, ==, stbuf.st_dev); + g_assert_cmpint (orig_stbuf.st_ino, ==, stbuf.st_ino); + + if (linkat (tmp_dfd, path, tmp_dfd, linkedpath, 0) < 0) + return glnx_throw_errno_prefix (error, "linkat"); + + if (!ostree_break_hardlink (tmp_dfd, path, TRUE, NULL, error)) + return FALSE; + if (!glnx_fstatat (tmp_dfd, path, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + /* This file should be different */ + g_assert_cmpint (orig_stbuf.st_dev, ==, stbuf.st_dev); + g_assert_cmpint (orig_stbuf.st_ino, !=, stbuf.st_ino); + /* But this one is still the same */ + if (!glnx_fstatat (tmp_dfd, linkedpath, &stbuf, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + g_assert_cmpint (orig_stbuf.st_dev, ==, stbuf.st_dev); + g_assert_cmpint (orig_stbuf.st_ino, ==, stbuf.st_ino); + + (void) unlinkat (tmp_dfd, path, 0); + (void) unlinkat (tmp_dfd, linkedpath, 0); + + return TRUE; +} + +static void +test_break_hardlink (void) +{ + int tmp_dfd = AT_FDCWD; + g_autoptr(GError) error = NULL; + + /* Regular file */ + const char hello_hardlinked_content[] = "hello hardlinked content"; + glnx_file_replace_contents_at (tmp_dfd, "test-hardlink", + (guint8*)hello_hardlinked_content, + strlen (hello_hardlinked_content), + GLNX_FILE_REPLACE_NODATASYNC, + NULL, &error); + g_assert_no_error (error); + (void)impl_test_break_hardlink (tmp_dfd, "test-hardlink", &error); + g_assert_no_error (error); + + /* Symlink */ + if (symlinkat ("some-path", tmp_dfd, "test-symhardlink") < 0) + err (1, "symlinkat"); + (void)impl_test_break_hardlink (tmp_dfd, "test-symhardlink", &error); + g_assert_no_error (error); +} + +static GVariant* +xattr_cb (OstreeRepo *repo, + const char *path, + GFileInfo *file_info, + gpointer user_data) +{ + GVariant *xattr = user_data; + if (g_str_equal (path, "/baz/cow")) + return g_variant_ref (xattr); + return NULL; +} + +/* check that using a devino cache doesn't cause us to ignore xattr callbacks */ +static void +test_devino_cache_xattrs (void) +{ + g_autoptr(GError) error = NULL; + gboolean ret = FALSE; + + g_autoptr(GFile) repo_path = g_file_new_for_path ("repo"); + + /* re-initialize as bare */ + ret = ot_test_run_libtest ("setup_test_repository bare", &error); + g_assert_no_error (error); + g_assert (ret); + + gboolean can_relabel; + ret = ot_check_relabeling (&can_relabel, &error); + g_assert_no_error (error); + g_assert (ret); + + gboolean has_user_xattrs; + ret = ot_check_user_xattrs (&has_user_xattrs, &error); + g_assert_no_error (error); + g_assert (ret); + + /* we need both because we're bare and our tests target user xattrs */ + if (!can_relabel || !has_user_xattrs) + { + g_test_skip ("this test requires full xattr support"); + return; + } + + g_autoptr(OstreeRepo) repo = ostree_repo_new (repo_path); + ret = ostree_repo_open (repo, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + g_autofree char *csum = NULL; + ret = ostree_repo_resolve_rev (repo, "test2", FALSE, &csum, &error); + g_assert_no_error (error); + g_assert (ret); + + g_autoptr(OstreeRepoDevInoCache) cache = ostree_repo_devino_cache_new (); + + OstreeRepoCheckoutAtOptions options = {0,}; + options.no_copy_fallback = TRUE; + options.devino_to_csum_cache = cache; + ret = ostree_repo_checkout_at (repo, &options, AT_FDCWD, "checkout", csum, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + g_autoptr(OstreeMutableTree) mtree = ostree_mutable_tree_new (); + g_autoptr(OstreeRepoCommitModifier) modifier = + ostree_repo_commit_modifier_new (0, NULL, NULL, NULL); + ostree_repo_commit_modifier_set_devino_cache (modifier, cache); + + g_auto(GVariantBuilder) builder; + g_variant_builder_init (&builder, (GVariantType*)"a(ayay)"); + g_variant_builder_add (&builder, "(@ay@ay)", + g_variant_new_bytestring ("user.myattr"), + g_variant_new_bytestring ("data")); + g_autoptr(GVariant) orig_xattrs = g_variant_ref_sink (g_variant_builder_end (&builder)); + + ret = ostree_repo_prepare_transaction (repo, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + ostree_repo_commit_modifier_set_xattr_callback (modifier, xattr_cb, NULL, orig_xattrs); + ret = ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, "checkout", + mtree, modifier, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + g_autoptr(GFile) root = NULL; + ret = ostree_repo_write_mtree (repo, mtree, &root, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* now check that the final xattr matches */ + g_autoptr(GFile) baz_child = g_file_get_child (root, "baz"); + g_autoptr(GFile) cow_child = g_file_get_child (baz_child, "cow"); + + g_autoptr(GVariant) xattrs = NULL; + ret = ostree_repo_file_get_xattrs (OSTREE_REPO_FILE (cow_child), &xattrs, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + gboolean found_xattr = FALSE; + gsize n = g_variant_n_children (xattrs); + for (gsize i = 0; i < n; i++) + { + const guint8* name; + const guint8* value; + g_variant_get_child (xattrs, i, "(^&ay^&ay)", &name, &value); + + if (g_str_equal ((const char*)name, "user.myattr")) + { + g_assert_cmpstr ((const char*)value, ==, "data"); + found_xattr = TRUE; + break; + } + } + + g_assert (found_xattr); + + OstreeRepoTransactionStats stats; + ret = ostree_repo_commit_transaction (repo, &stats, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* we should only have had to checksum /baz/cow */ + g_assert_cmpint (stats.content_objects_written, ==, 1); +} + +/* https://github.com/ostreedev/ostree/issues/1721 + * We should be able to commit large metadata objects now. + */ +static void +test_big_metadata (void) +{ + g_autoptr(GError) error = NULL; + gboolean ret = FALSE; + + g_autoptr(GFile) repo_path = g_file_new_for_path ("repo"); + + /* init as bare-user-only so we run everywhere */ + ret = ot_test_run_libtest ("setup_test_repository bare-user-only", &error); + g_assert_no_error (error); + g_assert (ret); + + g_autoptr(OstreeRepo) repo = ostree_repo_new (repo_path); + ret = ostree_repo_open (repo, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + g_autoptr(GFile) object_to_commit = NULL; + ret = ostree_repo_read_commit (repo, "test2", &object_to_commit, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + g_autoptr(OstreeMutableTree) mtree = ostree_mutable_tree_new (); + ret = ostree_repo_write_directory_to_mtree (repo, object_to_commit, mtree, NULL, + NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + const size_t len = 20 * 1024 * 1024; + g_assert_cmpint (len, >, OSTREE_MAX_METADATA_SIZE); + g_autofree char *large_buf = g_malloc (len); + memset (large_buf, 0x42, len); + g_autoptr(GVariantBuilder) builder = + g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_autofree char *commit_checksum = NULL; + g_variant_builder_add (builder, "{sv}", "large-value", + g_variant_new_fixed_array ((GVariantType*)"y", + large_buf, len, sizeof (char))); + ret = ostree_repo_write_commit (repo, NULL, NULL, NULL, g_variant_builder_end (builder), + OSTREE_REPO_FILE (object_to_commit), &commit_checksum, NULL, &error); + g_assert_no_error (error); + g_assert (ret); +} + +int main (int argc, char **argv) +{ + g_autoptr(GError) error = NULL; + glnx_unref_object OstreeRepo *repo = NULL; + + g_test_init (&argc, &argv, NULL); + + repo = ot_test_setup_repo (NULL, &error); + if (!repo) + goto out; + + g_test_add_data_func ("/repo-not-system", repo, test_repo_is_not_system); + g_test_add_data_func ("/raw-file-to-archive-stream", repo, test_raw_file_to_archive_stream); + g_test_add_data_func ("/objectwrites", repo, test_object_writes); + g_test_add_func ("/xattrs-devino-cache", test_devino_cache_xattrs); + g_test_add_func ("/break-hardlink", test_break_hardlink); + g_test_add_func ("/remotename", test_validate_remotename); + g_test_add_func ("/big-metadata", test_big_metadata); + + return g_test_run(); + out: + if (error) + g_error ("%s", error->message); + return 1; +} diff --git a/tests/test-basic-root.sh b/tests/test-basic-root.sh new file mode 100755 index 0000000..b06aa4a --- /dev/null +++ b/tests/test-basic-root.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +id=$(id -u) + +if test ${id} != 0; then + skip "continued basic tests must be run as root (possibly in a container)" +fi + +setup_test_repository "bare" + +echo "1..1" + +nextid=$(($id + 1)) + +rm checkout-test2 -rf +$OSTREE checkout test2 checkout-test2 +$OSTREE commit ${COMMIT_ARGS} -b test2 --tree=ref=test2 --owner-uid=$nextid +$OSTREE ls test2 baz/cow > ls.txt +assert_file_has_content ls.txt '-00644 '${nextid}' '${id} +# As bare and running as root (e.g. Docker container), do some ownership tests +# https://github.com/ostreedev/ostree/pull/801 +# Both hardlinks and copies should respect ownership, but we don't have -C yet; +# add it when we do. +for opt in -H; do + rm test2-co -rf + $OSTREE checkout ${opt} test2 test2-co + assert_streq "$(stat -c '%u' test2-co/baz/cow)" ${nextid} + assert_streq "$(stat -c '%u' test2-co/baz/alink)" ${nextid} +done +rm test2-co -rf +# But user mode doesn't +$OSTREE checkout -U test2 test2-co +assert_streq "$(stat -c '%u' test2-co/baz/cow)" ${id} +assert_streq "$(stat -c '%u' test2-co/baz/alink)" ${id} +echo "ok ownership" diff --git a/tests/test-basic-user-only.sh b/tests/test-basic-user-only.sh new file mode 100755 index 0000000..f65094f --- /dev/null +++ b/tests/test-basic-user-only.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +mode="bare-user-only" +setup_test_repository "$mode" +extra_basic_tests=5 +. $(dirname $0)/basic-test.sh + +$CMD_PREFIX ostree --version > version.yaml +python3 -c 'import yaml; yaml.safe_load(open("version.yaml"))' +echo "ok yaml version" + +# Reset things so we don't inherit a lot of state from earlier tests +cd ${test_tmpdir} +rm repo files -rf +ostree_repo_init repo init --mode=bare-user-only + +# Init an archive repo where we'll store content that can't go into bare-user +cd ${test_tmpdir} +rm repo-input -rf +ostree_repo_init repo-input init --mode=archive +cd ${test_tmpdir} +cat > statoverride.txt < files/some-setuid +chmod 0644 files/some-setuid +$CMD_PREFIX ostree --repo=repo-input commit -b content-with-suid --statoverride=statoverride.txt --tree=dir=files +if $CMD_PREFIX ostree pull-local --repo=repo repo-input 2>err.txt; then + assert_not_reached "copying suid file into bare-user worked?" +fi +assert_file_has_content err.txt "Content object.*invalid mode.*with bits 040.*" +echo "ok failed to commit suid" + +cd ${test_tmpdir} +rm repo-input -rf +ostree_repo_init repo-input init --mode=archive +rm files -rf && mkdir files +echo "a group writable file" > files/some-group-writable +chmod 0664 files/some-group-writable +$CMD_PREFIX ostree --repo=repo-input commit -b content-with-group-writable --tree=dir=files +$CMD_PREFIX ostree pull-local --repo=repo repo-input +$CMD_PREFIX ostree --repo=repo checkout -U -H content-with-group-writable groupwritable-co +assert_file_has_mode groupwritable-co/some-group-writable 664 +echo "ok supported group writable" + +cd ${test_tmpdir} +rm repo-input -rf +ostree_repo_init repo-input init --mode=archive +rm files -rf && mkdir files +mkdir files/worldwritable-dir +chmod a+w files/worldwritable-dir +$CMD_PREFIX ostree --repo=repo-input commit -b content-with-dir-world-writable --tree=dir=files +$CMD_PREFIX ostree pull-local --repo=repo repo-input +$CMD_PREFIX ostree --repo=repo checkout -U -H content-with-dir-world-writable dir-co +assert_file_has_mode dir-co/worldwritable-dir 775 +echo "ok didn't make world-writable dir" + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + rm repo-input -rf + rm repo -rf + ostree_repo_init repo init --mode=bare-user-only + ostree_repo_init repo-input init --mode=bare-user + rm files -rf && mkdir files + echo afile > files/afile + ln -s afile files/afile-link + $CMD_PREFIX ostree --repo=repo-input commit --canonical-permissions -b testtree --tree=dir=files + afile_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile) + afile_link_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile-link) + $CMD_PREFIX ostree pull-local --repo=repo repo-input + assert_files_hardlinked repo/${afile_relobjpath} repo-input/${afile_relobjpath} + if files_are_hardlinked repo/${afile_link_relobjpath} repo-input/${afile_link_relobjpath}; then + assert_not_reached "symlinks hardlinked across bare-user?" + fi + $OSTREE fsck -q + echo "ok hardlink pull from bare-user" +fi diff --git a/tests/test-basic-user.sh b/tests/test-basic-user.sh new file mode 100755 index 0000000..e56f828 --- /dev/null +++ b/tests/test-basic-user.sh @@ -0,0 +1,127 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_user_xattrs + +mode="bare-user" +setup_test_repository "$mode" + +extra_basic_tests=6 +. $(dirname $0)/basic-test.sh + +# Reset things so we don't inherit a lot of state from earlier tests +rm repo files -rf +setup_test_repository "bare-user" + +cd ${test_tmpdir} +objpath_nonexec=$(ostree_file_path_to_object_path repo test2 baz/cow) +assert_file_has_mode ${objpath_nonexec} 644 +objpath_ro=$(ostree_file_path_to_object_path repo test2 baz/cowro) +assert_file_has_mode ${objpath_ro} 600 +objpath_exec=$(ostree_file_path_to_object_path repo test2 baz/deeper/ohyeahx) +assert_file_has_mode ${objpath_exec} 755 +echo "ok bare-user committed modes" + +rm test2-checkout -rf +$OSTREE checkout -U -H test2 test2-checkout +cd test2-checkout +assert_file_has_mode baz/cow 644 +assert_file_has_mode baz/cowro 600 +assert_file_has_mode baz/deeper/ohyeahx 755 +echo "ok bare-user checkout modes" + +rm test2-checkout -rf +$OSTREE checkout -U -H test2 test2-checkout +touch test2-checkout/unwritable +chmod 0400 test2-checkout/unwritable +$OSTREE commit -b test2-unwritable --tree=dir=test2-checkout +chmod 0600 test2-checkout/unwritable +rm test2-checkout -rf +$OSTREE checkout -U -H test2-unwritable test2-checkout +cd test2-checkout +assert_file_has_mode unwritable 400 +echo "ok bare-user unwritable" + +rm test2-checkout -rf +$OSTREE checkout -U -H test2 test2-checkout +cat > statoverride.txt < components/dbus/usr/bin/dbus-daemon +chmod a+x components/dbus/usr/bin/dbus-daemon +echo dbus lib > components/dbus/usr/lib/libdbus.so.1 +echo dbus helper > components/dbus/usr/lib/dbus-daemon-helper +chmod a+x components/dbus/usr/lib/dbus-daemon-helper +echo systemd binary > components/systemd/usr/bin/systemd +chmod a+x components/systemd/usr/bin/systemd +echo systemd lib > components/systemd/usr/lib/libsystemd.so.1 + +# Make the gid on dbus 81 like fedora +$OSTREE commit -b component-dbus --owner-uid 0 --owner-gid 81 --tree=dir=components/dbus +$OSTREE commit -b component-systemd --owner-uid 0 --owner-gid 0 --tree=dir=components/systemd +rm rootfs -rf +for component in dbus systemd; do + $OSTREE checkout -U -H component-${component} --union rootfs +done +echo 'some rootfs data' > rootfs/usr/lib/cache.txt +$OSTREE commit -b rootfs --link-checkout-speedup --tree=dir=rootfs +$OSTREE ls rootfs /usr/bin/systemd >ls.txt +assert_file_has_content ls.txt '^-007.. 0 0 .*/usr/bin/systemd' +$OSTREE ls rootfs /usr/lib/dbus-daemon-helper >ls.txt +assert_file_has_content ls.txt '^-007.. 0 81 .*/usr/lib/dbus-daemon-helper' +echo "ok bare-user link-checkout-speedup maintains uids" + +cd ${test_tmpdir} +rm -rf test2-checkout +$OSTREE checkout -H -U test2 test2-checkout +# With --link-checkout-speedup, specifying --owner-uid should "win" by default. +myuid=$(id -u) +mygid=$(id -g) +newuid=$((${myuid} + 1)) +newgid=$((${mygid} + 1)) +$OSTREE commit ${COMMIT_ARGS} --owner-uid ${newuid} --owner-gid ${newgid} \ + --link-checkout-speedup -b test2-linkcheckout-test --tree=dir=test2-checkout +$OSTREE ls test2-linkcheckout-test /baz/cow > ls.txt +assert_file_has_content ls.txt "^-006.. ${newuid} ${newgid} .*/baz/cow" + +# But --devino-canonical should override that +$OSTREE commit ${COMMIT_ARGS} --owner-uid ${newuid} --owner-gid ${newgid} \ + -I -b test2-devino-test --table-output --tree=dir=test2-checkout > out.txt +$OSTREE ls test2-devino-test /baz/cow > ls.txt +assert_file_has_content ls.txt "^-006.. ${myuid} ${mygid} .*/baz/cow" +assert_file_has_content out.txt "Content Cache Hits: [1-9][0-9]*" + +$OSTREE refs --delete test2-{linkcheckout,devino}-test +echo "ok commit with -I" diff --git a/tests/test-basic.sh b/tests/test-basic.sh new file mode 100755 index 0000000..b1bc37e --- /dev/null +++ b/tests/test-basic.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_no_selinux_or_relabel + +mode="bare" +setup_test_repository "$mode" +. $(dirname $0)/basic-test.sh diff --git a/tests/test-bloom.c b/tests/test-bloom.c new file mode 100644 index 0000000..ea522ce --- /dev/null +++ b/tests/test-bloom.c @@ -0,0 +1,155 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include + +#include "ostree-bloom-private.h" + +/* Test the two different constructors work at a basic level. */ +static void +test_bloom_init (void) +{ + g_autoptr(OstreeBloom) bloom = NULL; + g_autoptr(GBytes) bytes = NULL; + + bloom = ostree_bloom_new (1, 1, ostree_str_bloom_hash); + g_assert_cmpuint (ostree_bloom_get_size (bloom), ==, 1); + g_assert_cmpuint (ostree_bloom_get_k (bloom), ==, 1); + g_assert (ostree_bloom_get_hash_func (bloom) == ostree_str_bloom_hash); + g_clear_pointer (&bloom, ostree_bloom_unref); + + bytes = g_bytes_new_take (g_malloc0 (4), 4); + bloom = ostree_bloom_new_from_bytes (bytes, 1, ostree_str_bloom_hash); + g_assert_cmpuint (ostree_bloom_get_size (bloom), ==, 4); + g_assert_cmpuint (ostree_bloom_get_k (bloom), ==, 1); + g_assert (ostree_bloom_get_hash_func (bloom) == ostree_str_bloom_hash); + g_clear_pointer (&bloom, ostree_bloom_unref); +} + +/* Test that building a bloom filter, marshalling it through GBytes, and loading + * it again, gives the same element membership. */ +static void +test_bloom_construction (void) +{ + g_autoptr(OstreeBloom) bloom = NULL; + g_autoptr(OstreeBloom) immutable_bloom = NULL; + g_autoptr(GBytes) bytes = NULL; + gsize i; + const gchar *members[] = + { + "hello", "there", "these", "are", "test", "strings" + }; + const gchar *non_members[] = + { + "not", "an", "element" + }; + const gsize n_bytes = 256; + const guint8 k = 8; + const OstreeBloomHashFunc hash = ostree_str_bloom_hash; + + /* Build a bloom filter. */ + bloom = ostree_bloom_new (n_bytes, k, hash); + + for (i = 0; i < G_N_ELEMENTS (members); i++) + ostree_bloom_add_element (bloom, members[i]); + + bytes = ostree_bloom_seal (bloom); + + /* Read it back from the GBytes. */ + immutable_bloom = ostree_bloom_new_from_bytes (bytes, k, hash); + + for (i = 0; i < G_N_ELEMENTS (members); i++) + g_assert_true (ostree_bloom_maybe_contains (bloom, members[i])); + + /* This should never fail in future, as we guarantee the hash function will + * never change. But given the definition of a bloom filter, it would also + * be valid for these calls to return %TRUE. */ + for (i = 0; i < G_N_ELEMENTS (non_members); i++) + g_assert_false (ostree_bloom_maybe_contains (bloom, non_members[i])); +} + +/* Test that an empty bloom filter definitely contains no elements. */ +static void +test_bloom_empty (void) +{ + g_autoptr(OstreeBloom) bloom = NULL; + const gsize n_bytes = 256; + const guint8 k = 8; + const OstreeBloomHashFunc hash = ostree_str_bloom_hash; + + /* Build an empty bloom filter. */ + bloom = ostree_bloom_new (n_bytes, k, hash); + + g_assert_false (ostree_bloom_maybe_contains (bloom, "hello")); + g_assert_false (ostree_bloom_maybe_contains (bloom, "there")); +} + +/* Build a bloom filter, and check the membership of the members as they are + * added. */ +static void +test_bloom_membership_during_construction (void) +{ + g_autoptr(OstreeBloom) bloom = NULL; + gsize i, j; + const gchar *members[] = + { + "hello", "there", "these", "are", "test", "strings" + }; + const gsize n_bytes = 256; + const guint8 k = 8; + const OstreeBloomHashFunc hash = ostree_str_bloom_hash; + + /* These membership checks should never fail in future, as we guarantee + * the hash function will never change. But given the definition of a bloom + * filter, it would also be valid for these checks to fail. */ + bloom = ostree_bloom_new (n_bytes, k, hash); + + for (i = 0; i < G_N_ELEMENTS (members); i++) + { + ostree_bloom_add_element (bloom, members[i]); + + for (j = 0; j < G_N_ELEMENTS (members); j++) + { + if (j <= i) + g_assert_true (ostree_bloom_maybe_contains (bloom, members[j])); + else + g_assert_false (ostree_bloom_maybe_contains (bloom, members[j])); + } + } +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/bloom/init", test_bloom_init); + g_test_add_func ("/bloom/construction", test_bloom_construction); + g_test_add_func ("/bloom/empty", test_bloom_empty); + g_test_add_func ("/bloom/membership-during-construction", test_bloom_membership_during_construction); + + return g_test_run(); +} diff --git a/tests/test-bsdiff.c b/tests/test-bsdiff.c new file mode 100644 index 0000000..a6b7fc0 --- /dev/null +++ b/tests/test-bsdiff.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libglnx.h" +#include "bsdiff/bsdiff.h" +#include "bsdiff/bspatch.h" +#include +#include +#include +#include + +static int +bzpatch_read (const struct bspatch_stream* stream, void* buffer, int length) +{ + GInputStream *in = stream->opaque; + if (length && ! g_input_stream_read (in, + buffer, + length, + NULL, + NULL)) + return -1; + + return 0; +} + +static int +bzdiff_write (struct bsdiff_stream* stream, const void* buffer, int size) +{ + GOutputStream *out = stream->opaque; + if (! g_output_stream_write (out, + buffer, + size, + NULL, + NULL)) + return -1; + + return 0; +} + +static void +test_bsdiff (void) +{ +#define OLD_SIZE 512 +#define NEW_SIZE (512+24) + + struct bsdiff_stream bsdiff_stream; + struct bspatch_stream bspatch_stream; + int i; + g_autofree guint8 *old = g_new (guint8, OLD_SIZE); + g_autofree guint8 *new = g_new (guint8, NEW_SIZE); + g_autofree guint8 *new_generated = g_new0 (guint8, NEW_SIZE); + g_autoptr(GOutputStream) out = g_memory_output_stream_new_resizable (); + g_autoptr(GInputStream) in = NULL; + + new[0] = 'A'; + for (i = 0; i < OLD_SIZE; i++) + { + old[i] = i; + new[i + 1] = old[i]; + } + for (i = OLD_SIZE + 1; i < NEW_SIZE; i++) + new[i] = i; + + bsdiff_stream.malloc = malloc; + bsdiff_stream.free = free; + bsdiff_stream.write = bzdiff_write; + bsdiff_stream.opaque = out; + g_assert_cmpint (bsdiff (old, OLD_SIZE, new, NEW_SIZE, &bsdiff_stream), ==, 0); + + g_assert (g_output_stream_close (out, NULL, NULL)); + + /* Now generate NEW_GENERATED from OLD and OUT. */ + { g_autoptr(GBytes) bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (out)); + in = g_memory_input_stream_new_from_bytes (bytes); + } + bspatch_stream.read = bzpatch_read; + bspatch_stream.opaque = in; + + g_assert_cmpint (bspatch (old, OLD_SIZE, new_generated, NEW_SIZE, &bspatch_stream), ==, 0); + + g_assert_cmpint (memcmp (new, new_generated, NEW_SIZE), ==, 0); +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/bsdiff", test_bsdiff); + return g_test_run(); +} diff --git a/tests/test-checksum.c b/tests/test-checksum.c new file mode 100644 index 0000000..8428155 --- /dev/null +++ b/tests/test-checksum.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libglnx.h" +#include +#include +#include +#include +#include "ostree-core-private.h" + +static void +test_ostree_parse_delta_name (void) +{ + { + g_autofree char *from = NULL; + g_autofree char *to = NULL; + g_assert (_ostree_parse_delta_name ("30d13b73cfe1e6988ffc345eac905f82a18def8ef1f0666fc392019e9eac388d", &from, &to, NULL)); + g_assert_cmpstr (to, ==, "30d13b73cfe1e6988ffc345eac905f82a18def8ef1f0666fc392019e9eac388d"); + g_assert_null (from); + } + + { + g_autofree char *from = NULL; + g_autofree char *to = NULL; + g_assert (_ostree_parse_delta_name ("30d13b73cfe1e6988ffc345eac905f82a18def8ef1f0666fc392019e9eac388d-5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03", &from, &to, NULL)); + g_assert_cmpstr (from, ==, "30d13b73cfe1e6988ffc345eac905f82a18def8ef1f0666fc392019e9eac388d"); + g_assert_cmpstr (to, ==, "5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03"); + } + + { + g_autofree char *from = NULL; + g_autofree char *to = NULL; + g_assert (!_ostree_parse_delta_name ("", &from, &to, NULL)); + g_assert_null (from); + g_assert_null (to); + } + + { + g_autofree char *from = NULL; + g_autofree char *to = NULL; + g_assert (!_ostree_parse_delta_name ("GARBAGE", &from, &to, NULL)); + g_assert_null (from); + g_assert_null (to); + } + + { + g_autofree char *from = NULL; + g_autofree char *to = NULL; + g_assert (!_ostree_parse_delta_name ("GARBAGE-5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03", &from, &to, NULL)); + g_assert_null (from); + g_assert_null (to); + } + + { + g_autofree char *from = NULL; + g_autofree char *to = NULL; + g_assert (!_ostree_parse_delta_name ("30d13b73cfe1e6988ffc345eac905f82a18def8ef1f0666fc392019e9eac388d-GARBAGE", &from, &to, NULL)); + g_assert_null (from); + g_assert_null (to); + } +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/ostree_parse_delta_name", test_ostree_parse_delta_name); + return g_test_run(); +} diff --git a/tests/test-commit-sign.sh b/tests/test-commit-sign.sh new file mode 100755 index 0000000..e9e7a6d --- /dev/null +++ b/tests/test-commit-sign.sh @@ -0,0 +1,142 @@ +#!/bin/bash +# +# Copyright (C) 2013 Jeremy Whiting +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +if ! has_gpgme; then + echo "1..0 #SKIP no gpg support compiled in" + exit 0 +fi + +echo "1..6" + +keyid="472CDAFA" +oldpwd=`pwd` +mkdir ostree-srv +cd ostree-srv +mkdir gnomerepo +ostree_repo_init gnomerepo --mode="archive" +mkdir gnomerepo-files +cd gnomerepo-files +echo first > firstfile +mkdir baz +echo moo > baz/cow +echo alien > baz/saucer +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "A remote commit" -m "Some Commit body" --gpg-sign=$keyid --gpg-homedir=${test_tmpdir}/gpghome +mkdir baz/deeper +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "Add deeper" --gpg-sign=$keyid --gpg-homedir=${test_tmpdir}/gpghome +echo hi > baz/deeper/ohyeah +mkdir baz/another/ +echo x > baz/another/y +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "The rest" --gpg-sign=$keyid --gpg-homedir=${test_tmpdir}/gpghome +cd .. + +cd ${test_tmpdir} +mkdir ${test_tmpdir}/httpd +cd httpd +ln -s ${test_tmpdir}/ostree-srv ostree +${OSTREE_HTTPD} --autoexit --daemonize -P 18081 -p ${test_tmpdir}/httpd-port +port=$(cat ${test_tmpdir}/httpd-port) +assert_streq $port 18081 +echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address +cd ${oldpwd} + +export OSTREE="${CMD_PREFIX} ostree --repo=repo" + +repopath=${test_tmpdir}/ostree-srv/gnomerepo +cp -a ${repopath} ${repopath}.orig + +# Set OSTREE_GPG_HOME to a place with no keyrings, we shouldn't trust the signature +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo +if env OSTREE_GPG_HOME=${test_tmpdir} ${CMD_PREFIX} ostree --repo=repo pull origin main; then + assert_not_reached "pull with no trusted GPG keys unexpectedly succeeded!" +fi +rm repo -rf +echo "ok pull no trusted GPG" + +# And a test case with valid signature +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo show --gpg-verify-remote=origin main > show.txt +assert_file_has_content_literal show.txt 'Found 1 signature' +rm repo -rf +echo "ok pull verify" + +# A test with corrupted detached signature +cd ${test_tmpdir} +find ${test_tmpdir}/ostree-srv/gnomerepo -name '*.commitmeta' | while read fname; do + echo borkborkbork > ${fname}; +done +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo +if ${CMD_PREFIX} ostree --repo=repo pull origin main; then + assert_not_reached "pull with corrupted signature unexpectedly succeeded!" +fi +rm repo -rf +echo "ok pull corrupted sig" + +# And now attempt to pull the same corrupted commit, but with GPG +# verification off +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo pull origin main +rm repo -rf +echo "ok repull corrupted" + +# Add an unsigned commit to the repo, then pull, then sign the commit, +# then pull again. Make sure we get the expected number of signatures +# each time. +cd ${test_tmpdir}/ostree-srv/gnomerepo-files +echo secret > signme +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "Don't forget to sign me!" +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo show main > show.txt +assert_not_file_has_content show.txt 'Found.*signature' +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo gpg-sign --gpg-homedir=${test_tmpdir}/gpghome main $keyid +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo show main > show.txt +assert_file_has_content_literal show.txt 'Found 1 signature' +echo "ok pull unsigned, then sign" + +# Delete the signature from the commit so the detached metadata is empty, +# then pull and verify the signature is also deleted on the client side. +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo gpg-sign --gpg-homedir=${test_tmpdir}/gpghome --delete main $keyid +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo show main >show.txt +assert_not_file_has_content show.txt 'Found.*signature' +echo "ok pull sig deleted" + +rm -rf repo gnomerepo-files diff --git a/tests/test-concurrency.py b/tests/test-concurrency.py new file mode 100755 index 0000000..e4ce21e --- /dev/null +++ b/tests/test-concurrency.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2017 Colin Walters +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +from __future__ import division +from __future__ import print_function +import os +import sys +import shutil +import subprocess +from multiprocessing import cpu_count + +def fatal(msg): + sys.stderr.write(msg) + sys.stderr.write('\n') + sys.exit(1) + +# Create 20 files with content based on @dname + a serial, basically to have +# different files with different checksums. +def mktree(dname, serial=0): + print('Creating tree', dname, file=sys.stderr) + os.mkdir(dname, 0o755) + for v in range(20): + with open('{}/{}'.format(dname, v), 'w') as f: + f.write('{} {} {}\n'.format(dname, serial, v)) + +subprocess.check_call(['ostree', '--repo=repo', 'init', '--mode=bare']) +# like the bit in libtest, but let's do it unconditionally since it's simpler, +# and we don't need xattr coverage for this +with open('repo/config', 'a') as f: + f.write('disable-xattrs=true\n') + +def commit(v): + tdir='tree{}'.format(v) + cmd = ['ostree', '--repo=repo', 'commit', '--fsync=0', '-b', tdir, '--tree=dir='+tdir] + proc = subprocess.Popen(cmd) + print('PID {}'.format(proc.pid), *cmd, file=sys.stderr) + return proc +def prune(): + cmd = ['ostree', '--repo=repo', 'prune', '--refs-only'] + proc = subprocess.Popen(cmd) + print('PID {}:'.format(proc.pid), *cmd, file=sys.stderr) + return proc + +def wait_check(proc): + pid = proc.pid + proc.wait() + if proc.returncode != 0: + sys.stderr.write("process {} exited with code {}\n".format(proc.pid, proc.returncode)) + return False + else: + sys.stderr.write('PID {} exited OK\n'.format(pid)) + return True + +print("1..2") + +def run(n_committers, n_pruners): + # The number of committers needs to be even since we only create half as + # many trees + n_committers += n_committers % 2 + + committers = set() + pruners = set() + + print('n_committers', n_committers, 'n_pruners', n_pruners, file=sys.stderr) + n_trees = n_committers // 2 + for v in range(n_trees): + mktree('tree{}'.format(v)) + + for v in range(n_committers): + committers.add(commit(v // 2)) + for v in range(n_pruners): + pruners.add(prune()) + + failed = False + for committer in committers: + if not wait_check(committer): + failed = True + for pruner in pruners: + if not wait_check(pruner): + failed = True + if failed: + fatal('A child process exited abnormally') + + for v in range(n_trees): + shutil.rmtree('tree{}'.format(v)) + +# No concurrent pruning +run(cpu_count() // 2 + 2, 0) +print("ok no concurrent prunes") + +run(cpu_count() // 2 + 4, 3) +print("ok concurrent prunes") diff --git a/tests/test-config.sh b/tests/test-config.sh new file mode 100755 index 0000000..2f44c30 --- /dev/null +++ b/tests/test-config.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# +# Copyright (C) 2018 Sinny Kumari +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..3' + +ostree_repo_init repo +${CMD_PREFIX} ostree remote add --repo=repo --set=xa.title=Flathub --set=xa.title-is-set=true flathub https://dl.flathub.org/repo/ +${CMD_PREFIX} ostree remote add --repo=repo org.mozilla.FirefoxRepo http://example.com/ostree/repo/ + +${CMD_PREFIX} ostree config --repo=repo get core.mode > list.txt +${CMD_PREFIX} ostree config --repo=repo get --group=core repo_version >> list.txt +${CMD_PREFIX} ostree config --repo=repo get --group='remote "flathub"' 'xa.title' >> list.txt +${CMD_PREFIX} ostree config --repo=repo get --group='remote "flathub"' 'xa.title-is-set' >> list.txt +${CMD_PREFIX} ostree config --repo=repo get --group='remote "org.mozilla.FirefoxRepo"' url >> list.txt +${CMD_PREFIX} cat list.txt + +assert_file_has_content list.txt "bare" +assert_file_has_content list.txt "1" +assert_file_has_content list.txt "Flathub" +assert_file_has_content list.txt "true" +assert_file_has_content list.txt "http://example\.com/ostree/repo/" + +# Check that it errors out if too many arguments are given +if ${CMD_PREFIX} ostree config --repo=repo get --group=core lock-timeout-secs extra 2>err.txt; then + assert_not_reached "ostree config get should error out if too many arguments are given" +fi +assert_file_has_content err.txt "error: Too many arguments given" +echo "ok config get" + +${CMD_PREFIX} ostree config --repo=repo set core.mode bare-user-only +${CMD_PREFIX} ostree config --repo=repo set --group='remote "flathub"' 'xa.title' 'Nightly Flathub' +${CMD_PREFIX} ostree config --repo=repo set --group='remote "flathub"' 'xa.title-is-set' 'false' +${CMD_PREFIX} ostree config --repo=repo set --group='remote "org.mozilla.FirefoxRepo"' url http://example.com/ostree/ + +assert_file_has_content repo/config "bare-user-only" +assert_file_has_content repo/config "Nightly Flathub" +assert_file_has_content repo/config "false" +assert_file_has_content repo/config "http://example\.com/ostree/" + +# Check that it errors out if too many arguments are given +if ${CMD_PREFIX} ostree config --repo=repo set --group=core lock-timeout-secs 120 extra 2>err.txt; then + assert_not_reached "ostree config set should error out if too many arguments are given" +fi +assert_file_has_content err.txt "error: Too many arguments given" +echo "ok config set" + +# Check that using `--` works and that "ostree config unset" works +${CMD_PREFIX} ostree config --repo=repo set core.lock-timeout-secs 60 +assert_file_has_content repo/config "lock-timeout-secs=60" +${CMD_PREFIX} ostree config --repo=repo -- set core.lock-timeout-secs -1 +assert_file_has_content repo/config "lock-timeout-secs=-1" +${CMD_PREFIX} ostree config --repo=repo unset core.lock-timeout-secs +assert_not_file_has_content repo/config "lock-timeout-secs=" + +# Check that "ostree config get" errors out on the key +if ${CMD_PREFIX} ostree config --repo=repo get core.lock-timeout-secs 2>err.txt; then + assert_not_reached "ostree config get should not work after unsetting a key" +fi +# Check for any character where quotation marks would be as they appear differently in the Fedora and Debian +# test suites (“” and '' respectively). See: https://github.com/ostreedev/ostree/pull/1839 +assert_file_has_content err.txt "error: Key file does not have key .lock-timeout-secs. in group .core." + +# Check that it's idempotent +${CMD_PREFIX} ostree config --repo=repo unset core.lock-timeout-secs +assert_not_file_has_content repo/config "lock-timeout-secs=" + +# Check that the group doesn't need to exist +${CMD_PREFIX} ostree config --repo=repo unset --group='remote "aoeuhtns"' 'xa.title' + +# Check that the key doesn't need to exist +${CMD_PREFIX} ostree config --repo=repo set --group='remote "aoeuhtns"' 'xa.title-is-set' 'false' +${CMD_PREFIX} ostree config --repo=repo unset --group='remote "aoeuhtns"' 'xa.title' + +# Check that it errors out if too many arguments are given +if ${CMD_PREFIX} ostree config --repo=repo unset core.lock-timeout-secs extra 2>err.txt; then + assert_not_reached "ostree config unset should error out if too many arguments are given" +fi +assert_file_has_content err.txt "error: Too many arguments given" +echo "ok config unset" diff --git a/tests/test-core.js b/tests/test-core.js new file mode 100755 index 0000000..a9ef891 --- /dev/null +++ b/tests/test-core.js @@ -0,0 +1,73 @@ +#!/usr/bin/env gjs +// +// Copyright (C) 2013 Colin Walters +// +// SPDX-License-Identifier: LGPL-2.0+ +// +// 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 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., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +const Gio = imports.gi.Gio; +const OSTree = imports.gi.OSTree; + +function assertEquals(a, b) { + if (a != b) + throw new Error("assertion failed " + JSON.stringify(a) + " == " + JSON.stringify(b)); +} + +print('1..1') + +let testDataDir = Gio.File.new_for_path('test-data'); +testDataDir.make_directory(null); +testDataDir.get_child('some-file').replace_contents("hello world!", null, false, 0, null); + +let repoPath = Gio.File.new_for_path('repo'); +let repo = OSTree.Repo.new(repoPath); +repo.create(OSTree.RepoMode.ARCHIVE_Z2, null); + +repo.open(null); + +assertEquals(repo.get_mode(), OSTree.RepoMode.ARCHIVE_Z2); + +repo.prepare_transaction(null); + +let mtree = OSTree.MutableTree.new(); +repo.write_directory_to_mtree(testDataDir, mtree, null, null); +let [,dirTree] = repo.write_mtree(mtree, null); +let [,commit] = repo.write_commit(null, 'Some subject', 'Some body', null, dirTree, null); +print("commit => " + commit); + +repo.commit_transaction(null, null); + +let [,root,checksum] = repo.read_commit(commit, null); +let child = root.get_child('some-file'); +let info = child.query_info("standard::name,standard::type,standard::size", 0, null); +assertEquals(info.get_size(), 12); + +// Write a ref and read it back +repo.prepare_transaction(null); +repo.transaction_set_refspec('someref', commit); +repo.commit_transaction(null, null); +let [,readCommit] = repo.resolve_rev('someref', false); +assertEquals(readCommit, commit); + +// Delete a ref +repo.prepare_transaction(null); +repo.transaction_set_refspec('someref', null); +repo.commit_transaction(null, null); +[,readCommit] = repo.resolve_rev('someref', true); +assertEquals(readCommit, null); + +print("ok test-core"); diff --git a/tests/test-corruption.sh b/tests/test-corruption.sh new file mode 100755 index 0000000..2b5e61b --- /dev/null +++ b/tests/test-corruption.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# +# Copyright (C) 2011,2017 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +echo "1..9" + +. $(dirname $0)/libtest.sh + +cd ${test_tmpdir} +rm repo files -rf +setup_test_repository "bare" +$OSTREE checkout test2 checkout-test2 +cd checkout-test2 +chmod o+x firstfile +if $OSTREE fsck -q; then + fatal "fsck unexpectedly succeeded" +fi +chmod o-x firstfile +$OSTREE fsck -q + +echo "ok chmod" + +cd ${test_tmpdir} +rm repo files -rf +setup_test_repository "bare" +rev=$($OSTREE rev-parse test2) +echo -n > repo/objects/${rev:0:2}/${rev:2}.commit +if $OSTREE fsck -q 2>err.txt; then + fatal "fsck unexpectedly succeeded" +fi +assert_file_has_content_literal err.txt "Corrupted commit object; checksum expected" + +echo "ok metadata checksum" + +cd ${test_tmpdir} +rm repo files -rf +setup_test_repository "bare" +rm checkout-test2 -rf +$OSTREE checkout test2 checkout-test2 +cd checkout-test2 +chmod o+x firstfile +if $OSTREE fsck -q --delete; then + fatal "fsck unexpectedly succeeded" +fi + +echo "ok chmod" + +cd ${test_tmpdir} +rm repo files -rf +setup_test_repository "bare" +find repo/ -name '*.commit' -delete +if $OSTREE fsck -q 2>err.txt; then + assert_not_reached "fsck unexpectedly succeeded" +fi +assert_file_has_content_literal err.txt "Loading commit for ref test2: No such metadata object" + +echo "ok missing commit" + +cd ${test_tmpdir} +tar xf ${test_srcdir}/ostree-path-traverse.tar.gz +if ${CMD_PREFIX} ostree --repo=ostree-path-traverse/repo fsck -q 2>err.txt; then + fatal "fsck unexpectedly succeeded" +fi +assert_file_has_content_literal err.txt '.dirtree: Invalid / in filename ../afile' +echo "ok path traverse fsck" + +cd ${test_tmpdir} +if ${CMD_PREFIX} ostree --repo=ostree-path-traverse/repo checkout pathtraverse-test pathtraverse-test 2>err.txt; then + fatal "checkout with path traversal unexpectedly succeeded" +fi +assert_file_has_content_literal err.txt 'Invalid / in filename ../afile' +echo "ok path traverse checkout" + +cd ${test_tmpdir} +rm repo files -rf +setup_test_repository "bare" + +rev=$($OSTREE rev-parse test2) + +filechecksum=$(ostree_file_path_to_checksum repo test2 /firstfile) +rm repo/$(ostree_checksum_to_relative_object_path repo $filechecksum) + +assert_not_has_file repo/state/${rev}.commitpartial + +if $OSTREE fsck -q 2>err.txt; then + assert_not_reached "fsck unexpectedly succeeded" +fi +assert_file_has_content_literal err.txt "Object missing" +assert_file_has_content_literal err.txt "Marking commit as partial: $rev" +assert_has_file repo/state/${rev}.commitpartial + +echo "ok missing file" + +cd ${test_tmpdir} +rm repo files -rf +setup_test_repository "bare" + +rev=$($OSTREE rev-parse test2) + +filechecksum=$(ostree_file_path_to_checksum repo test2 /firstfile) +echo corrupted >> repo/$(ostree_checksum_to_relative_object_path repo $filechecksum) +unset filechecksum + +assert_not_has_file repo/state/${rev}.commitpartial + +if $OSTREE fsck -q --delete 2>err.txt; then + assert_not_reached "fsck unexpectedly succeeded" +fi +assert_file_has_content_literal err.txt "Corrupted file object;" +assert_file_has_content_literal err.txt "Marking commit as partial: $rev" +assert_has_file repo/state/${rev}.commitpartial + +echo "ok corrupt file" + +cd ${test_tmpdir} +rm repo files -rf +setup_test_repository "bare" + +rev=$($OSTREE rev-parse test2) +firstfilechecksum=$(ostree_file_path_to_checksum repo test2 /firstfile) +echo corrupted >> repo/$(ostree_checksum_to_relative_object_path repo $firstfilechecksum) +secondfilechecksum=$(ostree_file_path_to_checksum repo test2 /baz/cow) +echo corrupted >> repo/$(ostree_checksum_to_relative_object_path repo $secondfilechecksum) + +assert_not_has_file repo/state/${rev}.commitpartial + +if $OSTREE fsck -a --delete 2>err.txt; then + assert_not_reached "fsck unexpectedly succeeded" +fi +assert_file_has_content err.txt "Corrupted file object.*${firstfilechecksum}" +assert_file_has_content err.txt "Corrupted file object.*${secondfilechecksum}" +assert_file_has_content_literal err.txt "Marking commit as partial: $rev" +assert_has_file repo/state/${rev}.commitpartial + +echo "ok fsck --all" diff --git a/tests/test-create-usb.sh b/tests/test-create-usb.sh new file mode 100755 index 0000000..8187ea7 --- /dev/null +++ b/tests/test-create-usb.sh @@ -0,0 +1,117 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Authors: +# - Philip Withnall + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_gpgme + +echo "1..5" + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo --collection-id org.example.Collection1 + +mkdir -p tree/root +touch tree/root/a + +# Add a few commits +seq 5 | while read i; do + echo a >> tree/root/a + ${CMD_PREFIX} ostree --repo=repo commit --branch=test-$i -m test -s test --gpg-homedir="${TEST_GPG_KEYHOME}" --gpg-sign="${TEST_GPG_KEYID_1}" tree +done + +${CMD_PREFIX} ostree --repo=repo summary --update --gpg-homedir="${TEST_GPG_KEYHOME}" --gpg-sign="${TEST_GPG_KEYID_1}" + +# Pull into a ‘local’ repository, to more accurately represent the situation of +# creating a USB stick from your local machine. +mkdir local-repo +${CMD_PREFIX} ostree --repo=local-repo init +${CMD_PREFIX} ostree --repo=local-repo remote add remote1 file://$(pwd)/repo --collection-id org.example.Collection1 --gpg-import="${test_tmpdir}/gpghome/key1.asc" +${CMD_PREFIX} ostree --repo=local-repo pull remote1 test-1 test-2 test-3 test-4 test-5 + +# Simple test to put two refs onto a USB stick. +mkdir dest-mount1 +${CMD_PREFIX} ostree --repo=local-repo create-usb dest-mount1 org.example.Collection1 test-1 org.example.Collection1 test-2 + +assert_has_dir dest-mount1/.ostree/repo +${CMD_PREFIX} ostree --repo=dest-mount1/.ostree/repo refs --collections > dest-refs +assert_file_has_content dest-refs "^(org\.example\.Collection1, test-1)$" +assert_file_has_content dest-refs "^(org\.example\.Collection1, test-2)$" +assert_not_file_has_content dest-refs "^(org\.example\.Collection1, test-3)$" +assert_has_file dest-mount1/.ostree/repo/summary + +echo "ok 1 simple usb" + +# Test that the repository can be placed in another standard location on the USB stick. +for dest in ostree/repo .ostree/repo; do + rm -rf dest-mount2 + mkdir dest-mount2 + ${CMD_PREFIX} ostree --repo=local-repo create-usb --destination-repo "$dest" dest-mount2 org.example.Collection1 test-1 + assert_has_dir "dest-mount2/$dest" + if [ -d dest-mount2/.ostree/repos.d ]; then + ls dest-mount2/.ostree/repos.d | wc -l > repo-links + assert_file_has_content repo-links "^0$" + fi +done + +echo "ok 2 usb in standard location" + +# Test that the repository can be placed in a non-standard location and gets a symlink to it. +mkdir dest-mount3 +${CMD_PREFIX} ostree --repo=local-repo create-usb --destination-repo some-dest dest-mount3 org.example.Collection1 test-1 +assert_has_dir "dest-mount3/some-dest" +assert_symlink_has_content "dest-mount3/.ostree/repos.d/00-generated" "/some-dest$" +${CMD_PREFIX} ostree --repo=dest-mount3/.ostree/repos.d/00-generated refs --collections > dest-refs +assert_file_has_content dest-refs "^(org\.example\.Collection1, test-1)$" +assert_has_file dest-mount3/.ostree/repos.d/00-generated/summary + +echo "ok 3 usb in non-standard location" + +# Test that adding an additional ref to an existing USB repository works. +${CMD_PREFIX} ostree --repo=local-repo create-usb --destination-repo some-dest dest-mount3 org.example.Collection1 test-2 org.example.Collection1 test-3 +assert_has_dir "dest-mount3/some-dest" +assert_symlink_has_content "dest-mount3/.ostree/repos.d/00-generated" "/some-dest$" +${CMD_PREFIX} ostree --repo=dest-mount3/.ostree/repos.d/00-generated refs --collections > dest-refs +assert_file_has_content dest-refs "^(org\.example\.Collection1, test-1)$" +assert_file_has_content dest-refs "^(org\.example\.Collection1, test-2)$" +assert_file_has_content dest-refs "^(org\.example\.Collection1, test-3)$" +${CMD_PREFIX} ostree --repo=dest-mount3/.ostree/repos.d/00-generated summary -v > dest-summary +assert_file_has_content dest-summary "(org\.example\.Collection1, test-1)$" +assert_file_has_content dest-summary "(org\.example\.Collection1, test-2)$" +assert_file_has_content dest-summary "(org\.example\.Collection1, test-3)$" + +echo "ok 4 adding ref to an existing usb" + +# Check that #OstreeRepoFinderMount works from a volume initialised uing create-usb. +mkdir finder-repo +ostree_repo_init finder-repo +${CMD_PREFIX} ostree --repo=finder-repo remote add remote1 file://$(pwd)/just-needed-for-the-keyring --collection-id org.example.Collection1 --gpg-import="${test_tmpdir}/gpghome/key1.asc" + +${test_builddir}/repo-finder-mount finder-repo dest-mount1 org.example.Collection1 test-1 org.example.Collection1 test-2 &> out +assert_file_has_content out "^0 .*_2Fdest-mount1_2F\.ostree_2Frepo_remote1\.trustedkeys\.gpg org\.example\.Collection1 test-1 $(ostree --repo=repo show test-1)$" +assert_file_has_content out "^0 .*_2Fdest-mount1_2F\.ostree_2Frepo_remote1\.trustedkeys\.gpg org\.example\.Collection1 test-2 $(ostree --repo=repo show test-2)$" + +echo "ok 5 find from usb repo" diff --git a/tests/test-delta.sh b/tests/test-delta.sh new file mode 100755 index 0000000..557447b --- /dev/null +++ b/tests/test-delta.sh @@ -0,0 +1,268 @@ +#!/bin/bash +# +# Copyright (C) 2011,2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_user_xattrs + +bindatafiles="bash true ostree" +morebindatafiles="false ls" + +echo '1..12' + +mkdir repo +ostree_repo_init repo --mode=archive + +mkdir files +for bin in ${bindatafiles}; do + cp $(which ${bin}) files +done + +${CMD_PREFIX} ostree --repo=repo commit -b test -s test --tree=dir=files + +function permuteFile() { + permutation=$(($1 % 2)) + output=$2 + case $permutation in + 0) dd if=/dev/zero count=40 bs=1 >> $output;; + 1) echo aheader | cat - $output >> $output.new && mv $output.new $output;; + esac +} + +function permuteDirectory() { + permutation=$1 + dir=$2 + for x in ${dir}/*; do + for z in $(seq ${permutation}); do + permuteFile ${z} ${x} + done + done +} + +get_assert_one_direntry_matching() { + local path=$1 + local r=$2 + local child="" + local bn + for p in ${path}/*; do + bn=$(basename $p) + if ! echo ${bn} | grep -q "$r"; then + continue + fi + if test -z "${child}"; then + child=${bn} + else + assert_not_reached "Expected only one child matching ${r} in ${path}"; + fi + done + if test -z "${child}"; then + assert_not_reached "Failed to find child matching ${r}" + fi + echo ${child} +} + +origrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test) + +${CMD_PREFIX} ostree --repo=repo static-delta generate --empty --to=${origrev} +${CMD_PREFIX} ostree --repo=repo static-delta generate --if-not-exists --empty --to=${origrev} > out.txt +assert_file_has_content out.txt "${origrev} already exists" +${CMD_PREFIX} ostree --repo=repo static-delta list | grep ${origrev} || exit 1 +${CMD_PREFIX} ostree --repo=repo prune +${CMD_PREFIX} ostree --repo=repo static-delta list | grep ${origrev} || exit 1 + +permuteDirectory 1 files +${CMD_PREFIX} ostree --repo=repo commit -b test -s test --tree=dir=files + +newrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test) + +${CMD_PREFIX} ostree --repo=repo static-delta generate --if-not-exists --from=${origrev} --to=${newrev} --inline +${CMD_PREFIX} ostree --repo=repo static-delta generate --if-not-exists --from=${origrev} --to=${newrev} --inline > out.txt +assert_file_has_content out.txt "${origrev}-${newrev} already exists" +# Should regenerate +${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline > out.txt +assert_not_file_has_content out.txt "${origrev}-${newrev} already exists" + +deltaprefix=$(get_assert_one_direntry_matching repo/deltas '.') +deltadir=$(get_assert_one_direntry_matching repo/deltas/${deltaprefix} '-') + +assert_has_file repo/deltas/${deltaprefix}/${deltadir}/superblock +assert_not_has_file repo/deltas/${deltaprefix}/${deltadir}/0 + +${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} + +assert_has_file repo/deltas/${deltaprefix}/${deltadir}/superblock +assert_has_file repo/deltas/${deltaprefix}/${deltadir}/0 + +${CMD_PREFIX} ostree --repo=repo static-delta generate --disable-bsdiff --from=${origrev} --to=${newrev} 2>&1 | grep "bsdiff=0 objects" +${CMD_PREFIX} ostree --repo=repo static-delta generate --max-bsdiff-size=0 --from=${origrev} --to=${newrev} 2>&1 | grep "bsdiff=0 objects" +${CMD_PREFIX} ostree --repo=repo static-delta generate --max-bsdiff-size=10000 --from=${origrev} --to=${newrev} 2>&1 | grep "bsdiff=[1-9]" + +${CMD_PREFIX} ostree --repo=repo static-delta list | grep ${origrev}-${newrev} || exit 1 + +if ${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --empty 2>>err.txt; then + assert_not_reached "static-delta generate --from=${origrev} --empty unexpectedly succeeded" +fi + +ostree_repo_init temp-repo --mode=archive +${CMD_PREFIX} ostree --repo=temp-repo pull-local repo +mkdir tmpsubdir +${CMD_PREFIX} ostree --repo=temp-repo static-delta generate --empty --to=${newrev} --filename=tmpsubdir/some.delta +assert_has_file tmpsubdir/some.delta +${CMD_PREFIX} ostree --repo=temp-repo static-delta list > delta-list.txt +assert_file_has_content delta-list.txt 'No static deltas' +rm temp-repo -rf + +echo 'ok generate' + +${CMD_PREFIX} ostree --repo=repo static-delta show ${origrev}-${newrev} > show.txt +assert_file_has_content show.txt "From: ${origrev}" +assert_file_has_content show.txt "To: ${newrev}" +assert_file_has_content show.txt 'Endianness: \(little\|big\)' + +echo 'ok show' + +${CMD_PREFIX} ostree --repo=repo static-delta generate --swap-endianness --from=${origrev} --to=${newrev} +${CMD_PREFIX} ostree --repo=repo static-delta show ${origrev}-${newrev} > show-swapped.txt +totalsize_orig=$(grep 'Total Size:' show.txt) +totalsize_swapped=$(grep 'Total Size:' show-swapped.txt) +assert_not_streq "${totalsize_orig}" "" +assert_streq "${totalsize_orig}" "${totalsize_swapped}" + +echo 'ok generate + show endian swapped' + +tar xf ${test_srcdir}/pre-endian-deltas-repo-big.tar.xz +mv pre-endian-deltas-repo{,-big} +tar xf ${test_srcdir}/pre-endian-deltas-repo-little.tar.xz +mv pre-endian-deltas-repo{,-little} +legacy_origrev=$(${CMD_PREFIX} ostree --repo=pre-endian-deltas-repo-big rev-parse main^) +legacy_newrev=$(${CMD_PREFIX} ostree --repo=pre-endian-deltas-repo-big rev-parse main) +${CMD_PREFIX} ostree --repo=pre-endian-deltas-repo-big static-delta show ${legacy_origrev}-${legacy_newrev} > show-legacy-big.txt +totalsize_legacy_big=$(grep 'Total Size:' show-legacy-big.txt) +${CMD_PREFIX} ostree --repo=pre-endian-deltas-repo-big static-delta show ${legacy_origrev}-${legacy_newrev} > show-legacy-little.txt +totalsize_legacy_little=$(grep 'Total Size:' show-legacy-little.txt) +for f in show-legacy-{big,little}.txt; do + if grep 'Endianness:.*heuristic' $f; then + found_heuristic=yes + break + fi +done +assert_streq "${found_heuristic}" "yes" +assert_streq "${totalsize_legacy_big}" "${totalsize_legacy_little}" + +echo 'ok heuristic endian detection' + +${CMD_PREFIX} ostree --repo=repo summary -u + +mkdir repo2 && ostree_repo_init repo2 --mode=bare-user +${CMD_PREFIX} ostree --repo=repo2 pull-local --require-static-deltas repo ${origrev} +${CMD_PREFIX} ostree --repo=repo2 fsck +${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null + +echo 'ok pull delta' + +rm repo2 -rf +mkdir repo2 && ostree_repo_init repo2 --mode=bare-user +mkdir deltadir + +deltaprefix=$(get_assert_one_direntry_matching repo/deltas '.') +deltadir=$(get_assert_one_direntry_matching repo/deltas/${deltaprefix} '-') +${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${origrev} +${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null +${CMD_PREFIX} ostree --repo=repo2 static-delta apply-offline repo/deltas/${deltaprefix}/${deltadir} +${CMD_PREFIX} ostree --repo=repo2 fsck +${CMD_PREFIX} ostree --repo=repo2 ls ${newrev} >/dev/null + +echo 'ok apply offline' + +rm -rf repo/deltas/${deltaprefix}/${deltadir}/* +${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline +assert_not_has_file repo/deltas/${deltaprefix}/${deltadir}/0 + +rm repo2 -rf +ostree_repo_init repo2 --mode=bare-user + +${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${origrev} +${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null +${CMD_PREFIX} ostree --repo=repo2 static-delta apply-offline repo/deltas/${deltaprefix}/${deltadir} +${CMD_PREFIX} ostree --repo=repo2 fsck +${CMD_PREFIX} ostree --repo=repo2 ls ${newrev} >/dev/null + +echo 'ok apply offline inline' + +${CMD_PREFIX} ostree --repo=repo static-delta list | grep ^${origrev}-${newrev}$ || exit 1 +${CMD_PREFIX} ostree --repo=repo static-delta list | grep ^${origrev}$ || exit 1 + +${CMD_PREFIX} ostree --repo=repo static-delta delete ${origrev} || exit 1 + +${CMD_PREFIX} ostree --repo=repo static-delta list | grep ^${origrev}-${newrev}$ || exit 1 +${CMD_PREFIX} ostree --repo=repo static-delta list | grep ^${origrev}$ && exit 1 + +${CMD_PREFIX} ostree --repo=repo static-delta delete ${origrev}-${newrev} || exit 1 + +${CMD_PREFIX} ostree --repo=repo static-delta list | grep ^${origrev}-${newrev}$ && exit 1 +${CMD_PREFIX} ostree --repo=repo static-delta list | grep ^${origrev}$ && exit 1 + +echo 'ok delete' + +# Make another commit with no changes to create a delta with no parts +${CMD_PREFIX} ostree --repo=repo commit -b test -s test --tree=dir=files +samerev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test) +${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${newrev} --to=${samerev} +${CMD_PREFIX} ostree --repo=repo static-delta show ${newrev}-${samerev} > show-empty.txt +nparts_empty=$(grep '^Number of parts:' show-empty.txt) +part0_meta_empty=$(grep '^PartMeta0:' show-empty.txt) +totalsize_empty=$(grep '^Total Uncompressed Size:' show-empty.txt) +assert_streq "${nparts_empty}" "Number of parts: 1" +assert_str_match "${part0_meta_empty}" "nobjects=0" +assert_streq "${totalsize_empty}" "Total Uncompressed Size: 0 (0 bytes)" + +echo 'ok generate + show empty delta part' + +${CMD_PREFIX} ostree --repo=repo summary -u + +rm -rf repo2 +mkdir repo2 && ostree_repo_init repo2 --mode=bare-user +${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${newrev} +${CMD_PREFIX} ostree --repo=repo2 pull-local --require-static-deltas repo ${samerev} +${CMD_PREFIX} ostree --repo=repo2 fsck +${CMD_PREFIX} ostree --repo=repo2 ls ${samerev} >/dev/null + +echo 'ok pull empty delta part' + +# Make a new branch to test "rebase deltas" +echo otherbranch-content > files/otherbranch-content +${CMD_PREFIX} ostree --repo=repo commit -b otherbranch --tree=dir=files +samerev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test) +${CMD_PREFIX} ostree --repo=repo static-delta generate --from=test --to=otherbranch +${CMD_PREFIX} ostree --repo=repo summary -u +${CMD_PREFIX} ostree --repo=repo2 pull-local --require-static-deltas repo otherbranch + +echo 'ok rebase deltas' + +${CMD_PREFIX} ostree --repo=repo summary -u +if ${CMD_PREFIX} ostree --repo=repo static-delta show GARBAGE 2> err.txt; then + assert_not_reached "static-delta show GARBAGE unexpectedly succeeded" +fi +assert_file_has_content err.txt "Invalid rev GARBAGE" + +echo 'ok handle bad delta name' diff --git a/tests/test-demo-buildsystem.sh b/tests/test-demo-buildsystem.sh new file mode 100755 index 0000000..c111919 --- /dev/null +++ b/tests/test-demo-buildsystem.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# +# Copyright (C) 2016 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_fuse +skip_without_user_xattrs + +echo "1..1" + +# Run "triggers" like ldconfig, gtk-update-icon-cache, etc. +demo_triggers() { + root=$1 + shift + mkdir -p ${root}/usr/lib + echo updated ldconfig at $(date) > ${root}/usr/lib/ld.so.cache.new + mv ${root}/usr/lib/ld.so.cache{.new,} +} + +# Make a binary in /usr/bin/$pkg which contains $version +exampleos_build_commit_package() { + pkg=$1 + version=$2 + mkdir -p ${pkg}-package/usr/bin/ + echo "${pkg}-content ${version}" > ${pkg}-package/usr/bin/${pkg} + # Use a dummy subject for this. + ${CMD_PREFIX} ostree --repo=build-repo commit -b exampleos/x86_64/${pkg} -s '' --tree=dir=${pkg}-package + rm ${pkg}-package -rf +} + +exampleos_recompose() { + rm exampleos-build -rf + for pkg in ${packages}; do + ${CMD_PREFIX} ostree --repo=build-repo checkout -U --union exampleos/x86_64/${pkg} exampleos-build + done + + # Now that we have our rootfs, run triggers + rofiles-fuse exampleos-build mnt + demo_triggers mnt/ + fusermount -u mnt + + # Then we commit it, using --link-checkout-speedup to effectively + # only re-checksum the ldconfig file. We also have dummy commit + # message here. + ${CMD_PREFIX} ostree --repo=build-repo commit -b exampleos/x86_64/standard -s 'exampleos build' --link-checkout-speedup exampleos-build +} + +packages="bash systemd" + +mkdir build-repo +ostree_repo_init build-repo --mode=bare-user +mkdir repo +ostree_repo_init repo --mode=archive +# Our FUSE mount point +mkdir mnt + +# "Build" some packages which are really just files with +# the version number inside. +exampleos_build_commit_package bash 0.4.7 +exampleos_build_commit_package systemd 224 + +# Now union the packages and commit +exampleos_recompose + +# This is our first commit - let's publish it. +${CMD_PREFIX} ostree --repo=repo pull-local build-repo exampleos/x86_64/standard + +# Now, update the bash package - this is a new commit on the branch +# exampleos/x86_64/bash. +exampleos_build_commit_package bash 0.5.0 + +# We now have two commits +exampleos_recompose + +# Publish again: +${CMD_PREFIX} ostree --repo=repo pull-local build-repo exampleos/x86_64/standard +# Optional: Generate a static delta vs the previous build +${CMD_PREFIX} ostree --repo=repo static-delta generate exampleos/x86_64/standard +# Optional: Regenerate the summary file +${CMD_PREFIX} ostree --repo=repo summary -u + +# Try: ostree --repo=demo-repo ls -R exampleos/x86_64/standard + +echo "ok demo buildsystem" diff --git a/tests/test-export.sh b/tests/test-export.sh new file mode 100755 index 0000000..17f7c02 --- /dev/null +++ b/tests/test-export.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# +# Copyright (C) 2016 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +if ! ostree --version | grep -q -e '- libarchive'; then + echo "1..0 #SKIP no libarchive support compiled in" + exit 0 +fi + +. $(dirname $0)/libtest.sh + +setup_test_repository "archive" + +echo '1..5' + +$OSTREE checkout test2 test2-co +$OSTREE commit --no-xattrs -b test2-noxattrs -s "test2 without xattrs" --tree=dir=test2-co +rm test2-co -rf + +cd ${test_tmpdir} +${OSTREE} 'export' test2-noxattrs -o test2.tar +mkdir t +(cd t && tar xf ../test2.tar) +${CMD_PREFIX} ostree --repo=repo diff --no-xattrs test2-noxattrs ./t > diff.txt +assert_file_empty diff.txt + +echo 'ok export gnutar diff (no xattrs)' + +cd ${test_tmpdir} +${OSTREE} 'export' test2-noxattrs --subpath=baz -o test2-subpath.tar +mkdir t2 +(cd t2 && tar xf ../test2-subpath.tar) +${CMD_PREFIX} ostree --repo=repo diff --no-xattrs ./t2 ./t/baz > diff.txt +assert_file_empty diff.txt + +echo 'ok export --subpath gnutar diff (no xattrs)' + +cd ${test_tmpdir} +${OSTREE} 'export' test2-noxattrs --prefix=the-prefix/ -o test2-prefix.tar +mkdir t3 +(cd t3 && tar xf ../test2-prefix.tar) +${CMD_PREFIX} ostree --repo=repo diff --no-xattrs test2-noxattrs ./t3/the-prefix > diff.txt +assert_file_empty diff.txt + +echo 'ok export --prefix gnutar diff (no xattrs)' + +cd ${test_tmpdir} +${OSTREE} 'export' test2-noxattrs --subpath=baz --prefix=the-prefix/ -o test2-prefix-subpath.tar +mkdir t4 +(cd t4 && tar xf ../test2-prefix-subpath.tar) +${CMD_PREFIX} ostree --repo=repo diff --no-xattrs ./t4/the-prefix ./t/baz > diff.txt +${CMD_PREFIX} ostree --repo=repo diff --no-xattrs test2-noxattrs ./t3/the-prefix > diff.txt +assert_file_empty diff.txt + +echo 'ok export --prefix --subpath gnutar diff (no xattrs)' + +rm test2.tar test2-subpath.tar diff.txt t t2 t3 t4 -rf + +cd ${test_tmpdir} +${OSTREE} 'export' test2 -o test2.tar +${OSTREE} commit -b test2-from-tar -s 'Import from tar' --tree=tar=test2.tar +${CMD_PREFIX} ostree --repo=repo diff test2 test2-from-tar +assert_file_empty diff.txt +rm test2.tar diff.txt t -rf + +echo 'ok export import' diff --git a/tests/test-find-remotes.sh b/tests/test-find-remotes.sh new file mode 100755 index 0000000..5dd880f --- /dev/null +++ b/tests/test-find-remotes.sh @@ -0,0 +1,240 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_gpgme + +echo '1..1' + +# Create two upstream collection repositories with some example commits +cd ${test_tmpdir} + +mkdir apps-collection +ostree_repo_init apps-collection --collection-id org.example.AppsCollection +mkdir -p files +pushd files +${CMD_PREFIX} ostree --repo=../apps-collection commit -s "Test apps-collection commit 1" -b app1 --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1} > ../app1-checksum +${CMD_PREFIX} ostree --repo=../apps-collection commit -s "Test apps-collection commit 2" -b app2 --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1} > ../app2-checksum +popd +${CMD_PREFIX} ostree --repo=apps-collection summary --update --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1} + +mkdir os-collection +ostree_repo_init os-collection --collection-id org.example.OsCollection +mkdir -p files +pushd files +${CMD_PREFIX} ostree --repo=../os-collection commit -s "Test os-collection commit 1" -b os/amd64/master --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_2} > ../os-checksum +popd +${CMD_PREFIX} ostree --repo=os-collection summary --update --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_2} + +# Create a local repository where we pull the branches from the two remotes as normal, using GPG. +mkdir local +ostree_repo_init local +${CMD_PREFIX} ostree --repo=local remote add apps-remote file://$(pwd)/apps-collection --collection-id org.example.AppsCollection --gpg-import=${test_tmpdir}/gpghome/key1.asc +${CMD_PREFIX} ostree --repo=local remote add os-remote file://$(pwd)/os-collection --collection-id org.example.OsCollection --gpg-import=${test_tmpdir}/gpghome/key2.asc + +${CMD_PREFIX} ostree --repo=local pull apps-remote app1 +${CMD_PREFIX} ostree --repo=local pull os-remote os/amd64/master + +${CMD_PREFIX} ostree --repo=local refs > refs +assert_file_has_content refs "^apps-remote:app1$" +assert_file_has_content refs "^os-remote:os/amd64/master$" + +${CMD_PREFIX} ostree --repo=local refs --collections > refs +cat refs | wc -l > refscount +assert_file_has_content refs "^(org\.example\.AppsCollection, app1)$" +assert_file_has_content refs "^(org\.example\.OsCollection, os/amd64/master)$" +assert_file_has_content refscount "^2$" + +# Create a local mirror repository where we pull the branches *in mirror mode* from the two remotes. +# This should pull them into refs/mirrors, since the remotes advertise a collection ID. +mkdir local-mirror +ostree_repo_init local-mirror +${CMD_PREFIX} ostree --repo=local-mirror remote add apps-remote file://$(pwd)/apps-collection --collection-id org.example.AppsCollection --gpg-import=${test_tmpdir}/gpghome/key1.asc +${CMD_PREFIX} ostree --repo=local-mirror remote add os-remote file://$(pwd)/os-collection --collection-id org.example.OsCollection --gpg-import=${test_tmpdir}/gpghome/key2.asc + +${CMD_PREFIX} ostree --repo=local-mirror pull --mirror apps-remote app1 +${CMD_PREFIX} ostree --repo=local-mirror pull --mirror os-remote os/amd64/master + +${CMD_PREFIX} ostree --repo=local-mirror refs | wc -l > refscount +assert_file_has_content refscount "^0$" +ls -1 local-mirror/refs/remotes | wc -l > remotescount +assert_file_has_content remotescount "^0$" + +${CMD_PREFIX} ostree --repo=local-mirror refs --collections > refs +assert_file_has_content refs "^(org\.example\.AppsCollection, app1)$" +assert_file_has_content refs "^(org\.example\.OsCollection, os/amd64/master)$" + +assert_file_has_content local-mirror/refs/mirrors/org.example.AppsCollection/app1 "^$(cat app1-checksum)$" +assert_file_has_content local-mirror/refs/mirrors/org.example.OsCollection/os/amd64/master "^$(cat os-checksum)$" + +for repo in local local-mirror; do + # Try finding an update for an existing branch. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config org.example.AppsCollection app1 > find + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/apps-collection$" + assert_file_has_content find "^ - Keyring: apps-remote\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.AppsCollection, app1) = $(cat app1-checksum)$" + assert_file_has_content find "^1/1 refs were found\.$" + assert_not_file_has_content find "^No results\.$" + + # Find several updates for several existing branches. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config org.example.AppsCollection app1 org.example.OsCollection os/amd64/master > find + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/apps-collection$" + assert_file_has_content find "^ - Keyring: apps-remote\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.AppsCollection, app1) = $(cat app1-checksum)$" + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/os-collection$" + assert_file_has_content find "^ - Keyring: os-remote\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.OsCollection, os/amd64/master) = $(cat os-checksum)$" + assert_file_has_content find "^2/2 refs were found\.$" + assert_not_file_has_content find "^No results\.$" + + # Find some updates and a new branch. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config org.example.AppsCollection app1 org.example.AppsCollection app2 org.example.OsCollection os/amd64/master > find + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/apps-collection$" + assert_file_has_content find "^ - Keyring: apps-remote\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.AppsCollection, app1) = $(cat app1-checksum)$" + assert_file_has_content find "^ - (org\.example\.AppsCollection, app2) = $(cat app2-checksum)$" + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/os-collection$" + assert_file_has_content find "^ - Keyring: os-remote\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.OsCollection, os/amd64/master) = $(cat os-checksum)$" + assert_file_has_content find "^3/3 refs were found\.$" + assert_not_file_has_content find "^No results\.$" + + # Find an update and a non-existent branch. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config org.example.AppsCollection app1 org.example.AppsCollection not-an-app > find + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/apps-collection$" + assert_file_has_content find "^ - Keyring: apps-remote\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.AppsCollection, not-an-app) = (not found)$" + assert_file_has_content find "^ - (org\.example\.AppsCollection, app1) = $(cat app1-checksum)$" + assert_file_has_content find "^Refs not found in any remote:$" + assert_file_has_content find "^ - (org\.example\.AppsCollection, not-an-app)$" + assert_file_has_content find "^1/2 refs were found\.$" + assert_not_file_has_content find "^No results\.$" + + # Do all the above, but pull this time. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config --pull org.example.AppsCollection app1 > pull || true + assert_file_has_content pull "^1/1 refs were found\.$" + assert_file_has_content pull "^Pulled 1/1 refs successfully\.$" + assert_not_file_has_content pull "Failed to pull some refs from the remotes" + assert_ref $repo app1 $(cat app1-checksum) + + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config --pull org.example.AppsCollection app1 org.example.OsCollection os/amd64/master > pull + assert_file_has_content pull "^2/2 refs were found\.$" + assert_file_has_content pull "^Pulled 2/2 refs successfully\.$" + assert_not_file_has_content pull "Failed to pull some refs from the remotes" + assert_ref $repo app1 $(cat app1-checksum) + assert_ref $repo os/amd64/master $(cat os-checksum) + + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config --pull org.example.AppsCollection app1 org.example.AppsCollection app2 org.example.OsCollection os/amd64/master > pull + assert_file_has_content pull "^3/3 refs were found\.$" + assert_file_has_content pull "^Pulled 3/3 refs successfully\.$" + assert_not_file_has_content pull "Failed to pull some refs from the remotes" + assert_ref $repo app1 $(cat app1-checksum) + assert_ref $repo app2 $(cat app2-checksum) + assert_ref $repo os/amd64/master $(cat os-checksum) + + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config --pull org.example.AppsCollection app1 org.example.AppsCollection not-an-app > pull + assert_file_has_content pull "^1/2 refs were found\.$" + assert_not_file_has_content pull "Failed to pull some refs from the remotes" + assert_ref $repo app1 $(cat app1-checksum) + assert_not_ref $repo not-an-app +done + +# Test pulling a new commit into the local mirror from one of the repositories. +pushd files +${CMD_PREFIX} ostree --repo=../os-collection commit -s "Test os-collection commit 2" -b os/amd64/master --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_2} > ../os-checksum-2 +popd +${CMD_PREFIX} ostree --repo=os-collection summary --update --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_2} + +for repo in local-mirror; do + # Try finding an update for that branch. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config org.example.OsCollection os/amd64/master > find + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/os-collection$" + assert_file_has_content find "^ - Keyring: os-remote\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.OsCollection, os/amd64/master) = $(cat os-checksum-2)$" + assert_file_has_content find "^1/1 refs were found\.$" + assert_not_file_has_content find "^No results\.$" + + # Pull it. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config --pull org.example.OsCollection os/amd64/master > pull || true + assert_file_has_content pull "^1/1 refs were found\.$" + assert_file_has_content pull "^Pulled 1/1 refs successfully\.$" + assert_not_file_has_content pull "Failed to pull some refs from the remotes" + assert_ref $repo os/amd64/master $(cat os-checksum-2) + + # We need to manually update the refs afterwards, since the original pull + # into the local-mirror was a --mirror pull — so it wrote refs/mirrors/blah. + # This pull was not, so it wrote refs/remotes/blah. + ${CMD_PREFIX} ostree --repo=$repo refs --collections --create org.example.OsCollection:os/amd64/master os-remote:os/amd64/master +done + +# Add the local mirror to the local repository as a remote, so that the local repo +# has two configured remotes for the os-collection. Ensure its summary is up to date first. +${CMD_PREFIX} ostree --repo=local-mirror summary --update +${CMD_PREFIX} ostree --repo=local remote add os-remote-local-mirror file://$(pwd)/local-mirror --collection-id org.example.OsCollection --gpg-import=${test_tmpdir}/gpghome/key2.asc + +for repo in local; do + # Try finding an update for that branch. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config org.example.OsCollection os/amd64/master > find + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/os-collection$" + assert_file_has_content find "^ - Keyring: os-remote\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.OsCollection, os/amd64/master) = $(cat os-checksum-2)$" + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/local-mirror$" + assert_file_has_content find "^ - Keyring: os-remote-local-mirror\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.OsCollection, os/amd64/master) = $(cat os-checksum-2)$" + assert_file_has_content find "^1/1 refs were found\.$" + assert_not_file_has_content find "^No results\.$" + + # Pull it. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config --pull org.example.OsCollection os/amd64/master > pull || true + assert_file_has_content pull "^1/1 refs were found\.$" + assert_file_has_content pull "^Pulled 1/1 refs successfully\.$" + assert_not_file_has_content pull "Failed to pull some refs from the remotes" + assert_ref $repo os/amd64/master $(cat os-checksum-2) +done + +# Add another commit to the OS collection, but don’t update the mirror. Then try pulling +# into the local repository again, and check that the outdated ref in the mirror is ignored. +pushd files +${CMD_PREFIX} ostree --repo=../os-collection commit -s "Test os-collection commit 3" -b os/amd64/master --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_2} > ../os-checksum-3 +popd +${CMD_PREFIX} ostree --repo=os-collection summary --update --gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_2} + +for repo in local; do + # Try finding an update for that branch. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config org.example.OsCollection os/amd64/master > find + assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/os-collection$" + assert_file_has_content find "^ - Keyring: os-remote\.trustedkeys\.gpg$" + assert_file_has_content find "^ - (org\.example\.OsCollection, os/amd64/master) = $(cat os-checksum-3)$" + assert_file_has_content find "^1/1 refs were found\.$" + assert_not_file_has_content find "^No results\.$" + + # Pull it. + ${CMD_PREFIX} ostree --repo=$repo find-remotes --finders=config --pull org.example.OsCollection os/amd64/master > pull || true + assert_file_has_content pull "^1/1 refs were found\.$" + assert_file_has_content pull "^Pulled 1/1 refs successfully\.$" + assert_not_file_has_content pull "Failed to pull some refs from the remotes" + assert_ref $repo os/amd64/master $(cat os-checksum-3) +done + +echo "ok find-remotes" diff --git a/tests/test-fsck-collections.sh b/tests/test-fsck-collections.sh new file mode 100755 index 0000000..dc6bcfe --- /dev/null +++ b/tests/test-fsck-collections.sh @@ -0,0 +1,211 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..11' + +cd ${test_tmpdir} + +# Create a new repository with one ref with the repository’s collection ID, and +# one ref with a different collection ID (which should be in refs/mirrors). +set_up_repo_with_collection_id() { + rm -rf repo files + + mkdir repo + ostree_repo_init repo --collection-id org.example.Collection + + mkdir files + pushd files + ${CMD_PREFIX} ostree --repo=../repo commit -s "Commit 1" -b ref1 > ../ref1-checksum + ${CMD_PREFIX} ostree --repo=../repo commit -s "Commit 2" --orphan --bind-ref ref2 --add-metadata-string=ostree.collection-binding=org.example.Collection2 > ../ref2-checksum + ${CMD_PREFIX} ostree --repo=../repo refs --collections --create=org.example.Collection2:ref2 $(cat ../ref2-checksum) + popd +} + +# Create a new repository with one ref and no collection IDs. +set_up_repo_without_collection_id() { + rm -rf repo files + + mkdir repo + ostree_repo_init repo + + mkdir files + pushd files + ${CMD_PREFIX} ostree --repo=../repo commit -s "Commit 3" -b ref3 --bind-ref ref4 > ../ref3-checksum + ${CMD_PREFIX} ostree --repo=../repo refs --create=ref4 $(cat ../ref3-checksum) + popd +} + +set_up_repo_with_collection_id + +# fsck at this point should succeed +${CMD_PREFIX} ostree fsck --repo=repo > fsck +assert_file_has_content fsck "^Validating refs in collections\.\.\.$" + +# Drop the commit the ref points to, and drop the original ref so that fsck doesn’t prematurely fail on that. +find repo/objects -name '*.commit' -delete -print | wc -l > commitcount +assert_file_has_content commitcount "^2$" + +rm repo/refs/heads/ref1 + +# fsck should now fail +if ${CMD_PREFIX} ostree fsck --repo=repo > fsck; then + assert_not_reached "fsck unexpectedly succeeded after deleting commit!" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck "^Validating refs in collections\.\.\.$" + +echo "ok 1 fsck-collections" + +# Try fsck in an old repository where refs/mirrors doesn’t exist to begin with. +# It should succeed. +set_up_repo_with_collection_id +rm -rf repo/refs/mirrors + +${CMD_PREFIX} ostree fsck --repo=repo > fsck +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck "^Validating refs in collections\.\.\.$" + +echo "ok 2 fsck-collections in old repository" + +# Test that fsck detects commits which are pointed to by refs, but which don’t +# list those refs in their ref-bindings. +set_up_repo_with_collection_id +${CMD_PREFIX} ostree --repo=repo refs --create=new-ref $(cat ref1-checksum) + +# For compatibility we don't check for this by default +${CMD_PREFIX} ostree fsck --repo=repo +# fsck should now fail +if ${CMD_PREFIX} ostree fsck --repo=repo --verify-bindings > fsck 2> fsck-error; then + assert_not_reached "fsck unexpectedly succeeded after adding unbound ref!" +fi +assert_file_has_content fsck-error "Commit has no requested ref ‘new-ref’ in ref binding metadata (‘ref1’)" +assert_file_has_content fsck "^Validating refs\.\.\.$" + +echo "ok 3 fsck detects missing ref bindings" + +# And the same where the ref is a collection–ref. +set_up_repo_with_collection_id +${CMD_PREFIX} ostree --repo=repo refs --collections --create=org.example.Collection2:new-ref $(cat ref1-checksum) + +# fsck should now fail +if ${CMD_PREFIX} ostree fsck --repo=repo --verify-bindings > fsck 2> fsck-error; then + assert_not_reached "fsck unexpectedly succeeded after adding unbound ref!" +fi +assert_file_has_content fsck-error "Commit has no requested ref ‘new-ref’ in ref binding metadata (‘ref1’)" +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck "^Validating refs in collections\.\.\.$" + +echo "ok 4 fsck detects missing collection–ref bindings" + +# Check that a ref with a different collection ID but the same ref name is caught. +set_up_repo_with_collection_id +${CMD_PREFIX} ostree --repo=repo refs --collections --create=org.example.Collection2:ref1 $(cat ref1-checksum) + +# fsck should now fail +if ${CMD_PREFIX} ostree fsck --repo=repo --verify-bindings > fsck 2> fsck-error; then + assert_not_reached "fsck unexpectedly succeeded after adding unbound ref!" +fi +assert_file_has_content fsck-error "Commit has collection ID ‘org\.example\.Collection’ in collection binding metadata, while the remote it came from has collection ID ‘org\.example\.Collection2’" +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck "^Validating refs in collections\.\.\.$" + +echo "ok 5 fsck detects missing collection–ref bindings" + +# Check that a commit with ref bindings which aren’t pointed to by refs is OK. +set_up_repo_with_collection_id +${CMD_PREFIX} ostree --repo=repo refs --delete ref1 + +# fsck at this point should succeed +${CMD_PREFIX} ostree fsck --repo=repo > fsck +assert_file_has_content fsck "^Validating refs in collections\.\.\.$" + +echo "ok 6 fsck ignores unreferenced ref bindings" + +# …but it’s not OK if we pass --verify-back-refs to fsck. +if ${CMD_PREFIX} ostree fsck --repo=repo --verify-back-refs > fsck 2> fsck-error; then + assert_not_reached "fsck unexpectedly succeeded after adding unbound ref!" +fi +assert_file_has_content fsck-error "Collection–ref (org\.example\.Collection, ref1) in bindings for commit .* does not exist" +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck "^Validating refs in collections\.\.\.$" + +echo "ok 7 fsck ignores unreferenced ref bindings" + +# +# Now repeat most of the above tests with a repository without collection IDs. +# + +set_up_repo_without_collection_id + +# fsck at this point should succeed +${CMD_PREFIX} ostree fsck --repo=repo --verify-bindings > fsck +assert_file_has_content fsck "^Validating refs in collections\.\.\.$" + +# Drop the commit the ref points to, and drop the original ref so that fsck doesn’t prematurely fail on that. +find repo/objects -name '*.commit' -delete -print | wc -l > commitcount +assert_file_has_content commitcount "^1$" + +rm repo/refs/heads/ref3 + +# fsck should now fail +if ${CMD_PREFIX} ostree fsck --repo=repo --verify-bindings > fsck; then + assert_not_reached "fsck unexpectedly succeeded after deleting commit!" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" + +echo "ok 8 fsck-collections" + +# Test that fsck detects commits which are pointed to by refs, but which don’t +# list those refs in their ref-bindings. +set_up_repo_without_collection_id +${CMD_PREFIX} ostree --repo=repo refs --create=new-ref $(cat ref3-checksum) + +# fsck should now fail +if ${CMD_PREFIX} ostree fsck --repo=repo --verify-bindings > fsck 2> fsck-error; then + assert_not_reached "fsck unexpectedly succeeded after adding unbound ref!" +fi +assert_file_has_content fsck-error "Commit has no requested ref ‘new-ref’ in ref binding metadata (‘ref3’, ‘ref4’)" +assert_file_has_content fsck "^Validating refs\.\.\.$" + +echo "ok 9 fsck detects missing ref bindings" + +# Check that a commit with ref bindings which aren’t pointed to by refs is OK. +set_up_repo_without_collection_id +${CMD_PREFIX} ostree --repo=repo refs --delete ref3 + +# fsck at this point should succeed +${CMD_PREFIX} ostree fsck --repo=repo > fsck +assert_file_has_content fsck "^Validating refs\.\.\.$" + +echo "ok 10 fsck ignores unreferenced ref bindings" + +# …but it’s not OK if we pass --verify-back-refs to fsck. +if ${CMD_PREFIX} ostree fsck --repo=repo --verify-back-refs > fsck 2> fsck-error; then + assert_not_reached "fsck unexpectedly succeeded after adding unbound ref!" +fi +assert_file_has_content fsck-error "Ref ‘ref3’ in bindings for commit .* does not exist" +assert_file_has_content fsck "^Validating refs\.\.\.$" + +echo "ok 11 fsck ignores unreferenced ref bindings" diff --git a/tests/test-fsck-delete.sh b/tests/test-fsck-delete.sh new file mode 100755 index 0000000..3e7347b --- /dev/null +++ b/tests/test-fsck-delete.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# +# Copyright © 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..6' + +cd ${test_tmpdir} + +rm -rf ./f1 +mkdir -p ./f1 +${CMD_PREFIX} ostree --repo=./f1 init --mode=archive-z2 +rm -rf ./trial +mkdir -p ./trial +echo test > ./trial/test +${CMD_PREFIX} ostree --repo=./f1 commit --tree=dir=./trial --skip-if-unchanged --branch=exp1 --subject="test Commit" + +rm -rf ./f2 +mkdir -p ./f2 +${CMD_PREFIX} ostree --repo=./f2 init --mode=archive-z2 +${CMD_PREFIX} ostree --repo=./f2 pull-local ./f1 +echo "ok 1 fsck-pre-commit" + +file=`find ./f2 |grep objects |grep \\.file |tail -1 ` +rm $file +echo whoops > $file + +# First check for corruption +if ${CMD_PREFIX} ostree fsck --repo=./f2 > fsck 2> fsck-error; then + assert_not_reached "fsck did not fail" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck-error "^error: In commits" + +echo "ok 2 fsck-fail-check" + +# Fix the corruption +if ${CMD_PREFIX} ostree fsck --delete --repo=./f2 > fsck 2> fsck-error; then + assert_not_reached "fsck did not fail" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck-error "^In commits" + +echo "ok 3 fsck-delete-check" + +# Check that fsck still exits with non-zero after corruption fix +if ${CMD_PREFIX} ostree fsck --repo=./f2 > fsck 2> fsck-error; then + assert_not_reached "fsck did not fail" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck-error "^error: 1" + +echo "ok 4 fsck-post-delete-check" + +${CMD_PREFIX} ostree --repo=./f2 pull-local ./f1 > /dev/null +echo "ok 5 fsck-repair" + +if ! ${CMD_PREFIX} ostree fsck --repo=./f2 > fsck 2> fsck-error; then + assert_not_reached "fsck failed when it should have passed" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_empty fsck-error +echo "ok 6 fsck-good" diff --git a/tests/test-gpg-signed-commit.sh b/tests/test-gpg-signed-commit.sh new file mode 100755 index 0000000..090b4bf --- /dev/null +++ b/tests/test-gpg-signed-commit.sh @@ -0,0 +1,329 @@ +#!/bin/bash +# +# Copyright (C) 2013 Jeremy Whiting +# Copyright (C) 2015 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +if ! has_gpgme; then + echo "1..0 #SKIP no gpgme support compiled in" + exit 0 +fi + +num_tests=1 + +# Run some more tests if an appropriate GPG is available +num_gpg_tests=8 +GPG=$(which_gpg) +if [ -n "${GPG}" ]; then + let num_tests+=num_gpg_tests +fi + +echo "1..${num_tests}" + +setup_test_repository "archive" + +export OSTREE_GPG_SIGN="${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME}" + +cd ${test_tmpdir} +${OSTREE} commit -b test2 -s "A GPG signed commit" -m "Signed commit body" --gpg-sign=${TEST_GPG_KEYID_1} --gpg-homedir=${TEST_GPG_KEYHOME} --tree=dir=files +${OSTREE} show test2 | grep -o 'Found [[:digit:]] signature' > test2-show +# We at least got some content here and ran through the code; later +# tests will actually do verification +assert_file_has_content test2-show 'Found 1 signature' + +${OSTREE} show --gpg-homedir=${TEST_GPG_KEYHOME} test2 | grep -o 'Found [[:digit:]] signature' > test2-show +assert_file_has_content test2-show 'Found 1 signature' + +# Now sign a commit with 3 different keys +cd ${test_tmpdir} +${OSTREE} commit -b test2 -s "A GPG signed commit" -m "Signed commit body" --gpg-sign=${TEST_GPG_KEYID_1} --gpg-sign=${TEST_GPG_KEYID_2} --gpg-sign=${TEST_GPG_KEYID_3} --gpg-homedir=${TEST_GPG_KEYHOME} --tree=dir=files +${OSTREE} show test2 | grep -o 'Found [[:digit:]] signature' > test2-show +assert_file_has_content test2-show 'Found 3 signature' + +# Commit and sign separately, then monkey around with signatures +cd ${test_tmpdir} +${OSTREE} commit -b test2 -s "A GPG signed commit" -m "Signed commit body" --tree=dir=files +if ${OSTREE} show test2 | grep -o 'Found [[:digit:]] signature'; then + assert_not_reached +fi +${OSTREE_GPG_SIGN} test2 ${TEST_GPG_KEYID_1} +${OSTREE} show test2 | grep -o 'Found [[:digit:]] signature' > test2-show +assert_file_has_content test2-show 'Found 1 signature' +# Signing with a previously used key should be caught +if ${OSTREE_GPG_SIGN} test2 ${TEST_GPG_KEYID_1} 2>/dev/null; then + assert_not_reached +fi +# Add a few more signatures and then delete them +${OSTREE_GPG_SIGN} test2 ${TEST_GPG_KEYID_2} ${TEST_GPG_KEYID_3} +${OSTREE} show test2 | grep -o 'Found [[:digit:]] signature' > test2-show +assert_file_has_content test2-show 'Found 3 signature' +${OSTREE_GPG_SIGN} --delete test2 ${TEST_GPG_KEYID_2} | grep -o 'Signatures deleted: [[:digit:]]' > test2-delete +assert_file_has_content test2-delete 'Signatures deleted: 1' +${OSTREE} show test2 | grep -o 'Found [[:digit:]] signature' > test2-show +assert_file_has_content test2-show 'Found 2 signature' +# Already deleted TEST_GPG_KEYID_2; should be ignored +${OSTREE_GPG_SIGN} --delete test2 ${TEST_GPG_KEYID_1} ${TEST_GPG_KEYID_2} ${TEST_GPG_KEYID_3} | grep -o 'Signatures deleted: [[:digit:]]' > test2-delete +assert_file_has_content test2-delete 'Signatures deleted: 2' +# Verify all signatures are gone +if ${OSTREE} show test2 | grep -o 'Found [[:digit:]] signature'; then + assert_not_reached +fi + +echo "ok" + +# Remaining tests require gpg +if [ -z "${GPG}" ]; then + exit 0 +fi + +# Although we have the gpg --set-expire option, we want to use it to set +# the expiration date for subkeys below. That was only added in gnupg +# 2.1.22. Check if SUBKEY-FPRS is in the usage output. +# (https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=NEWS;hb=HEAD) +if (${GPG} --quick-set-expire 2>&1 || :) | grep -q SUBKEY-FPRS; then + GPG_CAN_EXPIRE_SUBKEYS=true +else + GPG_CAN_EXPIRE_SUBKEYS=false +fi + +# Create a temporary GPG homedir +tmpgpg_home=${test_tmpdir}/tmpgpghome +mkdir -m700 ${tmpgpg_home} + +# Wire up an exit hook to kill the gpg-agent in it +cleanup_tmpgpg_home() { + libtest_cleanup_gpg ${tmpgpg_home} +} +libtest_exit_cmds+=(cleanup_tmpgpg_home) + +# Create an temporary trusted GPG directory +tmpgpg_trusted=${test_tmpdir}/tmpgpgtrusted +tmpgpg_trusted_keyring=${tmpgpg_trusted}/keyring.gpg +export OSTREE_GPG_HOME=${tmpgpg_trusted} +mkdir -p ${tmpgpg_trusted} + +# Create one normal signing key and one signing key with a subkey. See +# https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html. +${GPG} --homedir=${tmpgpg_home} --batch --generate-key <<"EOF" +Key-Type: RSA +Key-Length: 2048 +Key-Usage: sign +Name-Real: Test Key 1 +Expire-Date: 0 +%no-protection +%transient-key +%commit +Key-Type: RSA +Key-Length: 2048 +Key-Usage: sign +Subkey-Type: RSA +Subkey-Length: 2048 +Subkey-Usage: sign +Name-Real: Test Key 2 +Expire-Date: 0 +%no-protection +%transient-key +%commit +EOF + +# Figure out the key IDs and fingerprints. Assume that the order of the +# keys matches those specified in the generation. +# +# https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS +key1_id= +key1_fpr= +key2_id= +key2_fpr= +key2_sub_id= +key2_sub_fpr= +gpg_seckey_listing=$(${GPG} --homedir=${tmpgpg_home} --list-secret-keys --with-colons) +while IFS=: read -a fields; do + if [ "${fields[0]}" = sec ]; then + # Secret key - key ID is in field 5 + if [ -z "${key1_id}" ]; then + key1_id=${fields[4]} + else + key2_id=${fields[4]} + fi + elif [ "${fields[0]}" = ssb ]; then + # Secret subkey - key ID is in field 5 + key2_sub_id=${fields[4]} + elif [ "${fields[0]}" = fpr ]; then + # Fingerprint record - the fingerprint ID is in field 10 + if [ -z "${key1_fpr}" ]; then + key1_fpr=${fields[9]} + elif [ -z "${key2_fpr}" ]; then + key2_fpr=${fields[9]} + else + key2_sub_fpr=${fields[9]} + fi + fi +done <<< "${gpg_seckey_listing}" + +# Create a commit and sign it with both key1 and key2_sub +${OSTREE} commit -b test2 -s "A GPG signed commit" -m "Signed commit body" \ + --tree=dir=files --gpg-homedir=${tmpgpg_home} \ + --gpg-sign=${key1_id} --gpg-sign=${key2_sub_id} +${OSTREE} show test2 > test2-show +assert_file_has_content test2-show '^Found 2 signatures' +assert_file_has_content test2-show 'public key not found' +assert_file_has_content test2-show "${key1_id}" +assert_file_has_content test2-show "${key2_sub_id}" + +echo "ok signed with both generated keys" + +# Export the public keys and check again +${GPG} --homedir=${tmpgpg_home} --export ${key1_id} ${key2_id} > ${tmpgpg_trusted_keyring} +${OSTREE} show test2 > test2-show +assert_file_has_content test2-show '^Found 2 signatures' +assert_not_file_has_content test2-show 'public key not found' +assert_file_has_content test2-show "${key1_id}" +assert_file_has_content test2-show "${key2_sub_id}" +assert_file_has_content test2-show 'Good signature from "Test Key 1 <>"' +assert_file_has_content test2-show 'Good signature from "Test Key 2 <>"' +assert_file_has_content test2-show "Primary key ID ${key2_id}" + +echo "ok verified both generated keys" + +# Make key1 expired, wait until it's expired, export the public keys and check +# again +${GPG} --homedir=${tmpgpg_home} --quick-set-expire ${key1_fpr} seconds=1 +sleep 2 +${GPG} --homedir=${tmpgpg_home} --export ${key1_id} ${key2_id} > ${tmpgpg_trusted_keyring} +${OSTREE} show test2 > test2-show +assert_file_has_content test2-show '^Found 2 signatures' +assert_not_file_has_content test2-show 'public key not found' +assert_file_has_content test2-show "${key1_id}" +assert_file_has_content test2-show "${key2_sub_id}" +assert_file_has_content test2-show 'BAD signature from "Test Key 1 <>"' +assert_file_has_content test2-show 'Key expired' +assert_file_has_content test2-show 'Good signature from "Test Key 2 <>"' +assert_file_has_content test2-show "Primary key ID ${key2_id}" + +echo "ok verified with key1 expired" + +# Unexpire key1, expire key2 primary, wait until it's expired, export the +# public keys and check again +${GPG} --homedir=${tmpgpg_home} --quick-set-expire ${key1_fpr} seconds=0 +${GPG} --homedir=${tmpgpg_home} --quick-set-expire ${key2_fpr} seconds=1 +sleep 2 +${GPG} --homedir=${tmpgpg_home} --export ${key1_id} ${key2_id} > ${tmpgpg_trusted_keyring} +${OSTREE} show test2 > test2-show +assert_file_has_content test2-show '^Found 2 signatures' +assert_not_file_has_content test2-show 'public key not found' +assert_file_has_content test2-show "${key1_id}" +assert_file_has_content test2-show "${key2_sub_id}" +assert_file_has_content test2-show 'Good signature from "Test Key 1 <>"' +assert_file_has_content test2-show 'BAD signature from "Test Key 2 <>"' +assert_not_file_has_content test2-show 'Key expired' +assert_file_has_content test2-show "Primary key ID ${key2_id}" +assert_file_has_content test2-show 'Primary key expired' + +echo "ok verified with key2 primary expired" + +# If subkey expiration is available, expire key2 subkey, wait until it's +# expired, export the public keys and check again +if ${GPG_CAN_EXPIRE_SUBKEYS}; then + ${GPG} --homedir=${tmpgpg_home} --quick-set-expire ${key2_fpr} seconds=1 ${key2_sub_fpr} + sleep 2 + ${GPG} --homedir=${tmpgpg_home} --export ${key1_id} ${key2_id} > ${tmpgpg_trusted_keyring} + ${OSTREE} show test2 > test2-show + assert_file_has_content test2-show '^Found 2 signatures' + assert_not_file_has_content test2-show 'public key not found' + assert_file_has_content test2-show "${key1_id}" + assert_file_has_content test2-show "${key2_sub_id}" + assert_file_has_content test2-show 'Good signature from "Test Key 1 <>"' + assert_file_has_content test2-show 'BAD signature from "Test Key 2 <>"' + assert_file_has_content test2-show 'Key expired' + assert_file_has_content test2-show "Primary key ID ${key2_id}" + assert_file_has_content test2-show 'Primary key expired' + + echo "ok verified with key2 primary and subkey expired" +else + echo "ok # SKIP gpg --quick-set-expire does not support expiring subkeys" +fi + +# Unexpire key2 primary and export the public keys +${GPG} --homedir=${tmpgpg_home} --quick-set-expire ${key2_fpr} seconds=0 +${GPG} --homedir=${tmpgpg_home} --export ${key1_id} ${key2_id} > ${tmpgpg_trusted_keyring} + +# This test expects the subkey to be expired, so skip it if that didn't happen +if ${GPG_CAN_EXPIRE_SUBKEYS}; then + ${OSTREE} show test2 > test2-show + assert_file_has_content test2-show '^Found 2 signatures' + assert_not_file_has_content test2-show 'public key not found' + assert_file_has_content test2-show "${key1_id}" + assert_file_has_content test2-show "${key2_sub_id}" + assert_file_has_content test2-show 'Good signature from "Test Key 1 <>"' + assert_file_has_content test2-show 'BAD signature from "Test Key 2 <>"' + assert_file_has_content test2-show 'Key expired' + assert_file_has_content test2-show "Primary key ID ${key2_id}" + assert_not_file_has_content test2-show 'Primary key expired' + + echo "ok verified with key2 subkey expired" +else + echo "ok # SKIP gpg --quick-set-expire does not support expiring subkeys" +fi + +# Add a second subkey but don't export it to the trusted keyring so that a new +# commit signed with fails. +${GPG} --homedir=${tmpgpg_home} --batch --passphrase '' \ + --quick-add-key ${key2_fpr} rsa2048 sign never +gpg_seckey_listing=$(${GPG} --homedir=${tmpgpg_home} --list-secret-keys --with-colons) +key2_sub2_id=$(awk -F: '{if ($1 == "ssb") print $5}' <<< "${gpg_seckey_listing}" | tail -n1) +key2_sub2_fpr=$(awk -F: '{if ($1 == "fpr") print $10}' <<< "${gpg_seckey_listing}" | tail -n1) +${OSTREE} commit -b test2 -s "A GPG signed commit" -m "Signed commit body" \ + --tree=dir=files --gpg-homedir=${tmpgpg_home} \ + --gpg-sign=${key1_id} --gpg-sign=${key2_sub2_id} +${OSTREE} show test2 > test2-show +assert_file_has_content test2-show '^Found 2 signatures' +assert_file_has_content test2-show "${key1_id}" +assert_file_has_content test2-show "${key2_sub2_id}" +assert_file_has_content test2-show 'Good signature from "Test Key 1 <>"' +assert_file_has_content test2-show 'public key not found' + +echo "ok verified with key2 sub2 missing" + +# Revoke key1 by importing the revocation certificate created when generating +# the key. The cert should be in $homedir/openpgp-revocs.d/$fpr.rev with +# recent gnupg. However, it tries to prevent you from accidentally revoking +# things by adding a : before the block, so it needs to be stripped. +key1_rev=${tmpgpg_home}/openpgp-revocs.d/${key1_fpr}.rev +if [ -f ${key1_rev} ]; then + sed -i '/BEGIN PGP PUBLIC KEY BLOCK/s/^://' ${key1_rev} + ${GPG} --homedir=${tmpgpg_home} --import ${key1_rev} + # Export both keys again + ${GPG} --homedir=${tmpgpg_home} --export ${key1_id} ${key2_id} > ${tmpgpg_trusted_keyring} + ${OSTREE} show test2 > test2-show + assert_file_has_content test2-show '^Found 2 signatures' + assert_not_file_has_content test2-show 'public key not found' + assert_file_has_content test2-show "${key1_id}" + assert_file_has_content test2-show "${key2_sub2_id}" + assert_file_has_content test2-show 'Key revoked' + assert_file_has_content test2-show 'Good signature from "Test Key 2 <>"' + assert_file_has_content test2-show "Primary key ID ${key2_id}" + + echo "ok verified with key1 revoked" +else + echo "ok # SKIP could not find key revocation certificate" +fi diff --git a/tests/test-gpg-verify-result.c b/tests/test-gpg-verify-result.c new file mode 100644 index 0000000..5ae129b --- /dev/null +++ b/tests/test-gpg-verify-result.c @@ -0,0 +1,616 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include "libglnx.h" + +#include "ostree-gpg-verify-result-private.h" + +#define assert_no_gpg_error(err, filename) \ + G_STMT_START { \ + if (err != GPG_ERR_NO_ERROR) { \ + g_autoptr(GString) string = g_string_new ("assertion failed "); \ + g_string_append_printf (string, "%s: %s ", gpgme_strsource (err), gpgme_strerror (err)); \ + g_string_append (string, filename ? filename : ""); \ + g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, string->str); \ + } \ + } G_STMT_END + +#define assert_str_contains(s1, s2) \ + G_STMT_START { \ + const char *__s1 = (s1), *__s2 = (s2); \ + if (strstr (__s1, __s2) == NULL) { \ + g_autoptr(GString) string = g_string_new ("assertion failed (" #s1 " contains " #s2 "): "); \ + g_autofree char *__es1 = g_strescape (__s1, NULL); \ + g_autofree char *__es2 = g_strescape (__s2, NULL); \ + g_string_append_printf (string, "(\"%s\", \"%s\")", __es1, __es2); \ + g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, string->str); \ + } \ + } G_STMT_END + +typedef struct { + OstreeGpgVerifyResult *result; +} TestFixture; + +static OstreeGpgSignatureAttr some_attributes[] = { + OSTREE_GPG_SIGNATURE_ATTR_VALID, + OSTREE_GPG_SIGNATURE_ATTR_SIG_EXPIRED, + OSTREE_GPG_SIGNATURE_ATTR_KEY_EXPIRED, + OSTREE_GPG_SIGNATURE_ATTR_KEY_REVOKED, + OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING, + OSTREE_GPG_SIGNATURE_ATTR_KEY_EXP_TIMESTAMP, +}; + +static void +test_fixture_setup (TestFixture *fixture, + gconstpointer user_data) +{ + const char * const *sig_files = user_data; + gpgme_error_t gpg_error; + gpgme_data_t data_buffer; + gpgme_data_t signature_buffer; + OstreeGpgVerifyResult *result; + g_autofree char *homedir = NULL; + GError *local_error = NULL; + + /* Mimic what OstreeGpgVerifier does to create OstreeGpgVerifyResult. + * We don't use OstreeGpgVerifier directly because we don't need the + * multiple-keyring workaround and because we want the trust database + * taken into account, which contains additional data like revocation + * certificates for certain test cases. */ + + homedir = g_test_build_filename (G_TEST_DIST, "tests/gpg-verify-data", NULL); + g_setenv ("GNUPGHOME", homedir, TRUE); + + result = g_initable_new (OSTREE_TYPE_GPG_VERIFY_RESULT, + NULL, &local_error, NULL); + g_assert_no_error (local_error); + + g_autofree char *data_filename = g_build_filename (homedir, "lgpl2", NULL); + gpg_error = gpgme_data_new_from_file (&data_buffer, data_filename, 1); + assert_no_gpg_error (gpg_error, data_filename); + + if (sig_files == NULL) + { + /* No signature files specified, use full lgpl2.sig file */ + g_autofree char *filename = g_build_filename (homedir, "lgpl2.sig", NULL); + gpg_error = gpgme_data_new_from_file (&signature_buffer, filename, 1); + assert_no_gpg_error (gpg_error, filename); + } + else + { + /* Read all the specified files into the signature buffer */ + gpg_error = gpgme_data_new (&signature_buffer); + assert_no_gpg_error (gpg_error, NULL); + + for (const char * const *name = sig_files; *name != NULL; name++) + { + g_autofree char *path = g_build_filename (homedir, *name, NULL); + g_autoptr(GFile) sig_file = g_file_new_for_path (path); + + g_autofree char *contents = NULL; + gsize len; + g_assert_true (g_file_load_contents (sig_file, NULL, &contents, + &len, NULL, &local_error)); + g_assert_no_error (local_error); + + char *cur = contents; + while (len > 0) + { + ssize_t written = gpgme_data_write (signature_buffer, cur, len); + if (written == -1) + assert_no_gpg_error (gpgme_error_from_syserror (), path); + cur += written; + len -= written; + } + } + + gpgme_data_seek (signature_buffer, 0, SEEK_SET); + } + + gpg_error = gpgme_op_verify (result->context, + signature_buffer, data_buffer, NULL); + assert_no_gpg_error (gpg_error, NULL); + + result->details = gpgme_op_verify_result (result->context); + gpgme_result_ref (result->details); + + gpgme_data_release (data_buffer); + gpgme_data_release (signature_buffer); + + fixture->result = result; +} + +static void +test_fixture_teardown (TestFixture *fixture, + gconstpointer user_data) +{ + g_clear_object (&fixture->result); +} + +static void +test_check_counts (TestFixture *fixture, + gconstpointer user_data) +{ + guint count_all; + guint count_valid; + + count_all = ostree_gpg_verify_result_count_all (fixture->result); + count_valid = ostree_gpg_verify_result_count_valid (fixture->result); + + g_assert_cmpint (count_all, ==, 5); + g_assert_cmpint (count_valid, ==, 1); +} + +static void +test_signature_lookup (TestFixture *fixture, + gconstpointer user_data) +{ + /* Checking the signature with the revoked key for this case. */ + guint expected_signature_index = 2; + + /* Lowercase letters to ensure OstreeGpgVerifyResult handles it. */ + const char *fingerprint = "68dcc2db4bec5811c2573590bd9d2a44b7f541a6"; + + guint signature_index; + gboolean signature_found; + + /* Lookup full fingerprint. */ + signature_index = 999999; + signature_found = ostree_gpg_verify_result_lookup (fixture->result, + fingerprint, + &signature_index); + g_assert_true (signature_found); + g_assert_cmpint (signature_index, ==, expected_signature_index); + + /* Lookup abbreviated key ID. */ + signature_index = 999999; + signature_found = ostree_gpg_verify_result_lookup (fixture->result, + fingerprint + 32, + &signature_index); + g_assert_true (signature_found); + g_assert_cmpint (signature_index, ==, expected_signature_index); + + /* Bogus fingerprint, index should remain unchanged. */ + signature_index = expected_signature_index = 999999; + fingerprint = "CAFEBABECAFEBABECAFEBABECAFEBABECAFEBABE"; + signature_found = ostree_gpg_verify_result_lookup (fixture->result, + fingerprint, + &signature_index); + g_assert_false (signature_found); + g_assert_cmpint (signature_index, ==, expected_signature_index); +} + +static void +test_attribute_basics (TestFixture *fixture, + gconstpointer user_data) +{ + guint n_signatures, ii; + + n_signatures = ostree_gpg_verify_result_count_valid (fixture->result); + + for (ii = 0; ii < n_signatures; ii++) + { + g_autoptr(GVariant) tuple = NULL; + const char *attr_string; + const char *type_string; + gboolean key_missing; + + tuple = ostree_gpg_verify_result_get_all (fixture->result, ii); + + type_string = g_variant_get_type_string (tuple); + g_assert_cmpstr (type_string, ==, "(bbbbbsxxsssssxx)"); + + /* Check attributes which should be common to all signatures. */ + + g_variant_get_child (tuple, + OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, + "&s", &attr_string); + g_assert_cmpstr (attr_string, ==, "RSA"); + + g_variant_get_child (tuple, + OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME, + "&s", &attr_string); + g_assert_cmpstr (attr_string, ==, "SHA1"); + + g_variant_get_child (tuple, + OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING, + "b", &key_missing); + + g_variant_get_child (tuple, + OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, + "&s", &attr_string); + if (key_missing) + g_assert_cmpstr (attr_string, ==, "[unknown name]"); + else + g_assert_cmpstr (attr_string, ==, "J. Random User"); + + g_variant_get_child (tuple, + OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, + "&s", &attr_string); + if (key_missing) + g_assert_cmpstr (attr_string, ==, "[unknown email]"); + else + g_assert_cmpstr (attr_string, ==, "testcase@redhat.com"); + } +} + +static void +test_valid_signature (TestFixture *fixture, + gconstpointer user_data) +{ + guint signature_index = 0; + g_autoptr(GVariant) tuple = NULL; + gboolean valid; + gboolean sig_expired; + gboolean key_expired; + gboolean key_revoked; + gboolean key_missing; + gint64 key_exp_timestamp; + + tuple = ostree_gpg_verify_result_get (fixture->result, + signature_index, + some_attributes, + G_N_ELEMENTS (some_attributes)); + + g_variant_get (tuple, "(bbbbbx)", + &valid, + &sig_expired, + &key_expired, + &key_revoked, + &key_missing, + &key_exp_timestamp); + + g_assert_true (valid); + g_assert_false (sig_expired); + g_assert_false (key_expired); + g_assert_false (key_revoked); + g_assert_false (key_missing); + g_assert_cmpint (key_exp_timestamp, ==, 0); +} + +static void +test_expired_key (TestFixture *fixture, + gconstpointer user_data) +{ + guint signature_index = 1; + g_autoptr(GVariant) tuple = NULL; + gboolean valid; + gboolean sig_expired; + gboolean key_expired; + gboolean key_revoked; + gboolean key_missing; + gint64 key_exp_timestamp; + + tuple = ostree_gpg_verify_result_get (fixture->result, + signature_index, + some_attributes, + G_N_ELEMENTS (some_attributes)); + + g_variant_get (tuple, "(bbbbbx)", + &valid, + &sig_expired, + &key_expired, + &key_revoked, + &key_missing, + &key_exp_timestamp); + + g_assert_false (valid); + g_assert_false (sig_expired); + g_assert_true (key_expired); + g_assert_false (key_revoked); + g_assert_false (key_missing); + g_assert_cmpint (key_exp_timestamp, ==, 1426782201); +} + +static void +test_revoked_key (TestFixture *fixture, + gconstpointer user_data) +{ + guint signature_index = 2; + g_autoptr(GVariant) tuple = NULL; + gboolean valid; + gboolean sig_expired; + gboolean key_expired; + gboolean key_revoked; + gboolean key_missing; + gint64 key_exp_timestamp; + + tuple = ostree_gpg_verify_result_get (fixture->result, + signature_index, + some_attributes, + G_N_ELEMENTS (some_attributes)); + + g_variant_get (tuple, "(bbbbbx)", + &valid, + &sig_expired, + &key_expired, + &key_revoked, + &key_missing, + &key_exp_timestamp); + + g_assert_false (valid); + g_assert_false (sig_expired); + g_assert_false (key_expired); + g_assert_true (key_revoked); + g_assert_false (key_missing); + g_assert_cmpint (key_exp_timestamp, ==, 0); +} + +static void +test_missing_key (TestFixture *fixture, + gconstpointer user_data) +{ + guint signature_index = 3; + g_autoptr(GVariant) tuple = NULL; + gboolean valid; + gboolean sig_expired; + gboolean key_expired; + gboolean key_revoked; + gboolean key_missing; + gint64 key_exp_timestamp; + + tuple = ostree_gpg_verify_result_get (fixture->result, + signature_index, + some_attributes, + G_N_ELEMENTS (some_attributes)); + + g_variant_get (tuple, "(bbbbbx)", + &valid, + &sig_expired, + &key_expired, + &key_revoked, + &key_missing, + &key_exp_timestamp); + + g_assert_false (valid); + g_assert_false (sig_expired); + g_assert_false (key_expired); + g_assert_false (key_revoked); + g_assert_true (key_missing); + g_assert_cmpint (key_exp_timestamp, ==, 0); +} + +static void +test_expired_signature (TestFixture *fixture, + gconstpointer user_data) +{ + guint signature_index = 4; + g_autoptr(GVariant) tuple = NULL; + gboolean valid; + gboolean sig_expired; + gboolean key_expired; + gboolean key_revoked; + gboolean key_missing; + gint64 key_exp_timestamp; + + tuple = ostree_gpg_verify_result_get (fixture->result, + signature_index, + some_attributes, + G_N_ELEMENTS (some_attributes)); + + g_variant_get (tuple, "(bbbbbx)", + &valid, + &sig_expired, + &key_expired, + &key_revoked, + &key_missing, + &key_exp_timestamp); + + g_assert_false (valid); + g_assert_true (sig_expired); + g_assert_false (key_expired); + g_assert_false (key_revoked); + g_assert_false (key_missing); + g_assert_cmpint (key_exp_timestamp, ==, 0); +} + +static void +test_require_valid_signature (TestFixture *fixture, + gconstpointer user_data) +{ + GError *error = NULL; + gboolean res = ostree_gpg_verify_result_require_valid_signature (fixture->result, + &error); + g_assert_true (res); + g_assert_no_error (error); +} + +static void +test_require_valid_signature_expired_key (TestFixture *fixture, + gconstpointer user_data) +{ + GError *error = NULL; + gboolean res = ostree_gpg_verify_result_require_valid_signature (fixture->result, + &error); + g_assert_false (res); + g_assert_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_EXPIRED_KEY); + assert_str_contains (error->message, "Key expired"); +} + +static void +test_require_valid_signature_revoked_key (TestFixture *fixture, + gconstpointer user_data) +{ + GError *error = NULL; + gboolean res = ostree_gpg_verify_result_require_valid_signature (fixture->result, + &error); + g_assert_false (res); + g_assert_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_REVOKED_KEY); + assert_str_contains (error->message, "Key revoked"); +} + +static void +test_require_valid_signature_missing_key (TestFixture *fixture, + gconstpointer user_data) +{ + GError *error = NULL; + gboolean res = ostree_gpg_verify_result_require_valid_signature (fixture->result, + &error); + g_assert_false (res); + g_assert_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_MISSING_KEY); + assert_str_contains (error->message, "public key not found"); +} + +static void +test_require_valid_signature_expired_signature (TestFixture *fixture, + gconstpointer user_data) +{ + GError *error = NULL; + gboolean res = ostree_gpg_verify_result_require_valid_signature (fixture->result, + &error); + g_assert_false (res); + g_assert_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_EXPIRED_SIGNATURE); + assert_str_contains (error->message, "Signature expired"); +} + +static void +test_require_valid_signature_expired_missing_key (TestFixture *fixture, + gconstpointer user_data) +{ + GError *error = NULL; + gboolean res = ostree_gpg_verify_result_require_valid_signature (fixture->result, + &error); + g_assert_false (res); + + /* + * The error will be for the last signature, which is for a missing key, but + * the message should show both issues. + */ + g_assert_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_MISSING_KEY); + assert_str_contains (error->message, "Key expired"); + assert_str_contains (error->message, "public key not found"); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + (void) gpgme_check_version (NULL); + + g_test_add ("/gpg-verify-result/check-counts", + TestFixture, + NULL, + test_fixture_setup, + test_check_counts, + test_fixture_teardown); + + g_test_add ("/gpg-verify-result/signature-lookup", + TestFixture, + NULL, + test_fixture_setup, + test_signature_lookup, + test_fixture_teardown); + + g_test_add ("/gpg-verify-result/attribute-basics", + TestFixture, + NULL, + test_fixture_setup, + test_attribute_basics, + test_fixture_teardown); + + g_test_add ("/gpg-verify-result/valid-signature", + TestFixture, + NULL, + test_fixture_setup, + test_valid_signature, + test_fixture_teardown); + + g_test_add ("/gpg-verify-result/expired-key", + TestFixture, + NULL, + test_fixture_setup, + test_expired_key, + test_fixture_teardown); + + g_test_add ("/gpg-verify-result/revoked-key", + TestFixture, + NULL, + test_fixture_setup, + test_revoked_key, + test_fixture_teardown); + + g_test_add ("/gpg-verify-result/missing-key", + TestFixture, + NULL, + test_fixture_setup, + test_missing_key, + test_fixture_teardown); + + g_test_add ("/gpg-verify-result/expired-signature", + TestFixture, + NULL, + test_fixture_setup, + test_expired_signature, + test_fixture_teardown); + + g_test_add ("/gpg-verify-result/require-valid-signature", + TestFixture, + NULL, + test_fixture_setup, + test_require_valid_signature, + test_fixture_teardown); + + const char *expired_key_files[] = { "lgpl2.sig1", NULL }; + g_test_add ("/gpg-verify-result/require-valid-signature-expired-key", + TestFixture, + expired_key_files, + test_fixture_setup, + test_require_valid_signature_expired_key, + test_fixture_teardown); + + const char *revoked_key_files[] = { "lgpl2.sig2", NULL }; + g_test_add ("/gpg-verify-result/require-valid-signature-revoked-key", + TestFixture, + revoked_key_files, + test_fixture_setup, + test_require_valid_signature_revoked_key, + test_fixture_teardown); + + const char *missing_key_files[] = { "lgpl2.sig3", NULL }; + g_test_add ("/gpg-verify-result/require-valid-signature-missing-key", + TestFixture, + missing_key_files, + test_fixture_setup, + test_require_valid_signature_missing_key, + test_fixture_teardown); + + const char *expired_signature_files[] = { "lgpl2.sig4", NULL }; + g_test_add ("/gpg-verify-result/require-valid-signature-expired-signature", + TestFixture, + expired_signature_files, + test_fixture_setup, + test_require_valid_signature_expired_signature, + test_fixture_teardown); + + const char *expired_missing_key_files[] = { "lgpl2.sig1", "lgpl2.sig3", NULL }; + g_test_add ("/gpg-verify-result/require-valid-signature-expired-missing-key", + TestFixture, + expired_missing_key_files, + test_fixture_setup, + test_require_valid_signature_expired_missing_key, + test_fixture_teardown); + + return g_test_run (); +} diff --git a/tests/test-help.sh b/tests/test-help.sh new file mode 100755 index 0000000..912e41b --- /dev/null +++ b/tests/test-help.sh @@ -0,0 +1,100 @@ +#!/bin/bash +# +# Copyright (C) 2014 Owen Taylor +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..1" + +test_usage_output() { + file=$1; shift + cmd=$1; shift + assert_file_has_content $file '^Usage' + # check that it didn't print twice somehow + if [ "$(grep --count '^Usage' $file)" != 1 ]; then + _fatal_print_file "$file" "File '$file' has '^Usage' more than once." + fi + assert_file_has_content $file "$cmd" +} + +# check that we found at least one command with subcommands +found_subcommands=0 + +test_recursive() { + local cmd=$1 + + echo "$cmd" 1>&2 + $cmd --help 1>out 2>err + # --help message goes to standard output + test_usage_output out "$cmd" + assert_file_empty err + + # Select the list of commands, for each line, remove the leading spaces, and take the first word(command) of each line + builtins=`sed -n '/^Builtin \("[^"]*" \)\?Commands:$/,/^$/p' out 2>err || rc=$? + if [ $rc = 0 ] ; then + assert_not_reached "missing subcommand but 0 exit status" + fi + + # error message and usage goes to standard error + test_usage_output err "$cmd" + assert_file_has_content err 'No \("[^"]*" sub\)\?command specified' + assert_file_empty out + + rc=0 + $cmd non-existent-subcommand 1>out 2>err || rc=$? + if [ $rc = 0 ] ; then + assert_not_reached "non-existent subcommand but 0 exit status" + fi + + test_usage_output err "$cmd" + assert_file_has_content err 'Unknown \("[^"]*" sub\)\?command' + assert_file_empty out + + for subcmd in $builtins; do + case "$subcmd" in + (trivial-httpd) + # Skip trivial-httpd if enabled, it doesn't work + # uninstalled (and also doesn't produce the output + # we expect). + ;; + (*) + test_recursive "$cmd $subcmd" + ;; + esac + done + fi +} + +test_recursive ostree +if [ $found_subcommands != 1 ]; then + assert_not_reached "no ostree commands with subcommands found!" +fi + +echo "ok help option is properly supported" diff --git a/tests/test-include-ostree-h.c b/tests/test-include-ostree-h.c new file mode 100644 index 0000000..af41bb3 --- /dev/null +++ b/tests/test-include-ostree-h.c @@ -0,0 +1,45 @@ +/* + * Copyright © 2018 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Matthew Leeds + */ + +#include "config.h" + +#include +#include +#include + +static void +test_include_ostree_h_compiled (void) +{ +} + +/* Just ensure that we can compile with ostree.h included */ +int main (int argc, char **argv) +{ + setlocale (LC_ALL, ""); + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/include-ostree-h/compiled", test_include_ostree_h_compiled); + + return g_test_run(); +} diff --git a/tests/test-init-collections.sh b/tests/test-init-collections.sh new file mode 100755 index 0000000..1954f1a --- /dev/null +++ b/tests/test-init-collections.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..1' + +cd ${test_tmpdir} + +# Check that initialising a repository with a collection ID results in the ID being in the config. +mkdir repo +ostree_repo_init repo --collection-id org.example.Collection +assert_file_has_content repo/config "^collection-id=org\.example\.Collection$" + +echo "ok init-collections" diff --git a/tests/test-kargs.c b/tests/test-kargs.c new file mode 100644 index 0000000..d837055 --- /dev/null +++ b/tests/test-kargs.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "ostree-kernel-args.h" +#include "otutil.h" + +static gboolean +check_string_existance (OstreeKernelArgs *karg, + const char *string_to_find) +{ + g_autofree gchar* string_with_spaces = ostree_kernel_args_to_string (karg); + g_auto(GStrv) string_list = g_strsplit (string_with_spaces, " ", -1); + return g_strv_contains ((const char* const*) string_list, string_to_find); +} + +static gboolean +kernel_args_entry_value_equal (gconstpointer data, + gconstpointer value) +{ + const OstreeKernelArgsEntry *e = data; + return g_strcmp0 (_ostree_kernel_args_entry_get_value (e), value) == 0; +} + +static gboolean +kernel_args_entry_key_equal (gconstpointer data, + gconstpointer key) +{ + const OstreeKernelArgsEntry *e = data; + return g_strcmp0 (_ostree_kernel_args_entry_get_key (e), key) == 0; +} + +static void +test_kargs_delete (void) +{ + g_autoptr(GError) error = NULL; + gboolean ret; + __attribute__((cleanup(ostree_kernel_args_cleanup))) OstreeKernelArgs *karg = ostree_kernel_args_new (); + + ostree_kernel_args_append (karg, "single_key=test"); + ostree_kernel_args_append (karg, "test=firstval"); + ostree_kernel_args_append (karg, "test=secondval"); + ostree_kernel_args_append (karg, "test="); + ostree_kernel_args_append (karg, "test"); + + /* Delete a non-existant key should fail */ + ret = ostree_kernel_args_delete (karg, "non_existant_key", &error); + g_assert (!ret); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); + + /* Delete a key with multiple values when only specifying key should work if a no-value + * variant exists */ + ret = ostree_kernel_args_delete (karg, "test", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (!check_string_existance (karg, "test")); + + /* Trying again now should fail since there are only kargs with various values */ + ret = ostree_kernel_args_delete (karg, "test", &error); + g_assert (!ret); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); + + /* Delete a key with a non existant value should fail */ + ret = ostree_kernel_args_delete (karg, "test=non_existant_value", &error); + g_assert (!ret); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); + + /* Delete a key with only one value should fail if the value doesn't match */ + ret = ostree_kernel_args_delete (karg, "single_key=non_existent_value", &error); + g_assert (!ret); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); + + /* Delete a key with only one value should succeed by only specifying key */ + ret = ostree_kernel_args_delete (karg, "single_key", &error); + g_assert_no_error (error); + g_assert (ret); + /* verify the value array is properly updated */ + GPtrArray *kargs_array = _ostree_kernel_arg_get_key_array (karg); + g_assert (!ot_ptr_array_find_with_equal_func (kargs_array, "single_key", kernel_args_entry_value_equal, NULL)); + g_assert (!check_string_existance (karg, "single_key")); + + /* Delete specific key/value pair */ + ret = ostree_kernel_args_delete (karg, "test=secondval", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (!check_string_existance (karg, "test=secondval")); + + /* Delete key/value pair with empty string value */ + ret = ostree_kernel_args_delete (karg, "test=", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (!check_string_existance (karg, "test=")); + + ret = ostree_kernel_args_delete (karg, "test=firstval", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (!check_string_existance (karg, "test=firstval")); + + /* Check that we can delete duplicate keys */ + ostree_kernel_args_append (karg, "test=foo"); + ostree_kernel_args_append (karg, "test=foo"); + check_string_existance (karg, "test=foo"); + ret = ostree_kernel_args_delete (karg, "test=foo", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (check_string_existance (karg, "test=foo")); + ret = ostree_kernel_args_delete (karg, "test=foo", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (!check_string_existance (karg, "test=foo")); + + /* Make sure we also gracefully do this for key-only args */ + ostree_kernel_args_append (karg, "nosmt"); + ostree_kernel_args_append (karg, "nosmt"); + check_string_existance (karg, "nosmt"); + ret = ostree_kernel_args_delete (karg, "nosmt", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (check_string_existance (karg, "nosmt")); + ret = ostree_kernel_args_delete (karg, "nosmt", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (!check_string_existance (karg, "nosmt")); +} + +static void +test_kargs_replace (void) +{ + g_autoptr(GError) error = NULL; + gboolean ret; + __attribute__((cleanup(ostree_kernel_args_cleanup))) OstreeKernelArgs *karg = ostree_kernel_args_new (); + + ostree_kernel_args_append (karg, "single_key"); + ostree_kernel_args_append (karg, "test=firstval"); + ostree_kernel_args_append (karg, "test=secondval"); + + /* Replace when the input key is non-existant should fail */ + ret = ostree_kernel_args_new_replace (karg, "nonexistantkey", &error); + g_assert (!ret); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); + + /* Replace non-existant value with input key=nonexistantvalue=newvalue should fail */ + ret = ostree_kernel_args_new_replace (karg, "single_key=nonexistantval=newval", &error); + g_assert (!ret); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); + + /* Replace with input key=value will fail for a key with multiple values */ + ret = ostree_kernel_args_new_replace (karg, "test=newval", &error); + g_assert (!ret); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); + + /* Replace with input key=value for a key with single value should succeed + * Also note, we also allow ''(empty string) valid to be a value + */ + ret = ostree_kernel_args_new_replace (karg, "single_key=newvalue", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (!check_string_existance (karg, "single_key")); + g_assert (check_string_existance (karg, "single_key=newvalue")); + + /* Replace with input key=value=newvalue if key and value both + * exist, the action should succeed + */ + ret = ostree_kernel_args_new_replace (karg, "test=firstval=newval", &error); + g_assert_no_error (error); + g_assert (ret); + g_assert (!check_string_existance (karg, "test=firstval")); + g_assert (check_string_existance (karg, "test=newval")); +} + +/* In this function, we want to verify that ostree_kernel_args_append + * and ostree_kernel_args_to_string is correct. After that + * we will use these two functions(append and tostring) in other tests: delete and replace + */ +static void +test_kargs_append (void) +{ + __attribute__((cleanup(ostree_kernel_args_cleanup))) OstreeKernelArgs *append_arg = ostree_kernel_args_new (); + /* Some valid cases (key=value) pair */ + ostree_kernel_args_append (append_arg, "test=valid"); + ostree_kernel_args_append (append_arg, "test=secondvalid"); + ostree_kernel_args_append (append_arg, "test="); + ostree_kernel_args_append (append_arg, "test"); + ostree_kernel_args_append (append_arg, "second_test"); + + /* We loops through the kargs inside table to verify + * the functionality of append because at this stage + * we have yet to find the conversion kargs to string fully "functional" + */ + GHashTable *kargs_table = _ostree_kernel_arg_get_kargs_table (append_arg); + GLNX_HASH_TABLE_FOREACH_KV (kargs_table, const char*, key, GPtrArray*, value_array) + { + if (g_str_equal (key, "test")) + { + g_assert (ot_ptr_array_find_with_equal_func (value_array, "valid", kernel_args_entry_value_equal, NULL)); + g_assert (ot_ptr_array_find_with_equal_func (value_array, "secondvalid", kernel_args_entry_value_equal, NULL)); + g_assert (ot_ptr_array_find_with_equal_func (value_array, "", kernel_args_entry_value_equal, NULL)); + g_assert (ot_ptr_array_find_with_equal_func (value_array, NULL, kernel_args_entry_value_equal, NULL)); + } + else + { + g_assert_cmpstr (key, ==, "second_test"); + g_assert (ot_ptr_array_find_with_equal_func (value_array, NULL, kernel_args_entry_value_equal, NULL)); + } + } + + /* verify the value array is properly updated */ + GPtrArray *kargs_array = _ostree_kernel_arg_get_key_array (append_arg); + g_assert (ot_ptr_array_find_with_equal_func (kargs_array, "test", kernel_args_entry_key_equal, NULL)); + g_assert (ot_ptr_array_find_with_equal_func (kargs_array, "second_test", kernel_args_entry_key_equal, NULL)); + + /* Up till this point, we verified that the above was all correct, we then + * check ostree_kernel_args_to_string has the right result + */ + g_autofree gchar* kargs_str = ostree_kernel_args_to_string (append_arg); + g_auto(GStrv) kargs_list = g_strsplit(kargs_str, " ", -1); + g_assert (g_strv_contains ((const char* const *)kargs_list, "test=valid")); + g_assert (g_strv_contains ((const char* const *)kargs_list, "test=secondvalid")); + g_assert (g_strv_contains ((const char* const *)kargs_list, "test=")); + g_assert (g_strv_contains ((const char* const *)kargs_list, "test")); + g_assert (g_strv_contains ((const char* const *)kargs_list, "second_test")); + g_assert_cmpint (5, ==, g_strv_length (kargs_list)); +} + +int +main (int argc, + char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/kargs/kargs_append", test_kargs_append); + g_test_add_func ("/kargs/kargs_delete", test_kargs_delete); + g_test_add_func ("/kargs/kargs_replace", test_kargs_replace); + return g_test_run (); +} diff --git a/tests/test-keyfile-utils.c b/tests/test-keyfile-utils.c new file mode 100644 index 0000000..3014cf1 --- /dev/null +++ b/tests/test-keyfile-utils.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include +#include "ot-keyfile-utils.h" + +static GKeyFile *g_keyfile; + +static void +test_get_boolean_with_default (void) +{ + g_autoptr(GError) error = NULL; + gboolean out = FALSE; + + g_assert (ot_keyfile_get_boolean_with_default (g_keyfile, + "section", + "a_boolean_true", + FALSE, + &out, + &error)); + g_assert_true (out); + + g_assert (ot_keyfile_get_boolean_with_default (g_keyfile, + "section", + "a_boolean_false", + TRUE, + &out, + &error)); + g_assert_false (out); + + g_assert (ot_keyfile_get_boolean_with_default (g_keyfile, + "section", + "a_not_existing_boolean", + TRUE, + &out, + &error)); + g_assert_true (out); + + g_clear_error (&error); + g_assert (ot_keyfile_get_boolean_with_default (g_keyfile, + "a_fake_section", + "a_boolean_true", + FALSE, + &out, + &error)); +} + +static void +test_get_value_with_default (void) +{ + g_autoptr(GError) error = NULL; + g_autofree char *out = NULL; + GLogLevelFlags always_fatal_mask; + const char *section = "section"; + + /* Avoid that g_return_val_if_fail causes the test to fail. */ + always_fatal_mask = g_log_set_always_fatal (0); + + g_assert_false (ot_keyfile_get_value_with_default (g_keyfile, + NULL, + "value_foo", + "none", + &out, + &error)); + g_clear_pointer (&out, g_free); + g_assert_false (ot_keyfile_get_value_with_default (g_keyfile, + section, + NULL, + "none", + &out, + &error)); + g_clear_pointer (&out, g_free); + g_assert_false (ot_keyfile_get_value_with_default (g_keyfile, + section, + NULL, + "something", + &out, + &error)); + g_clear_pointer (&out, g_free); + + /* Restore the old mask. */ + g_log_set_always_fatal (always_fatal_mask); + + g_assert (ot_keyfile_get_value_with_default (g_keyfile, + section, + "value_foo", + "none", + &out, + &error)); + g_assert_cmpstr (out, ==, "foo"); + g_clear_pointer (&out, g_free); + + g_assert (ot_keyfile_get_value_with_default (g_keyfile, + section, + "a_not_existing_value", + "correct", + &out, + &error)); + g_assert_cmpstr (out, ==, "correct"); + g_clear_pointer (&out, g_free); + + g_assert (ot_keyfile_get_value_with_default (g_keyfile, + "a_fake_section", + "a_value_true", + "no value", + &out, + &error)); + g_assert_cmpstr (out, ==, "no value"); + g_clear_pointer (&out, g_free); +} + +static void +test_get_value_with_default_group_optional (void) +{ + g_autoptr(GError) error = NULL; + g_autofree char *out = NULL; + GLogLevelFlags always_fatal_mask; + const char *section = "section"; + +/* Avoid that g_return_val_if_fail causes the test to fail. */ + always_fatal_mask = g_log_set_always_fatal (0); + + g_assert_false (ot_keyfile_get_value_with_default_group_optional (g_keyfile, + NULL, + "value_foo", + "none", + &out, + &error)); + g_clear_pointer (&out, g_free); + g_assert_false (ot_keyfile_get_value_with_default_group_optional (g_keyfile, + section, + NULL, + "none", + &out, + &error)); + g_clear_pointer (&out, g_free); + g_assert_false (ot_keyfile_get_value_with_default_group_optional (g_keyfile, + section, + NULL, + "something", + &out, + &error)); + g_clear_pointer (&out, g_free); + + /* Restore the old mask. */ + g_log_set_always_fatal (always_fatal_mask); + + g_assert (ot_keyfile_get_value_with_default_group_optional (g_keyfile, + section, + "value_foo", + "none", + &out, + &error)); + g_assert_cmpstr (out, ==, "foo"); + g_clear_pointer (&out, g_free); + + g_assert (ot_keyfile_get_value_with_default_group_optional (g_keyfile, + section, + "a_not_existing_value", + "correct", + &out, + &error)); + g_assert_cmpstr (out, ==, "correct"); + g_clear_pointer (&out, g_free); + + g_assert (ot_keyfile_get_value_with_default_group_optional (g_keyfile, + "an_optional_section", + "a_value_true", + "no value", + &out, + &error)); + g_clear_error (&error); + g_clear_pointer (&out, g_free); +} + +static void +test_copy_group (void) +{ + gsize length, length2; + const char *section = "section"; + GLogLevelFlags always_fatal_mask; + + /* Avoid that g_return_val_if_fail causes the test to fail. */ + always_fatal_mask = g_log_set_always_fatal (0); + + g_autoptr(GKeyFile) tmp = g_key_file_new (); + + g_assert_false (ot_keyfile_copy_group (NULL, tmp, section)); + g_assert_false (ot_keyfile_copy_group (g_keyfile, NULL, section)); + g_assert_false (ot_keyfile_copy_group (g_keyfile, tmp, NULL)); + + /* Restore the old mask. */ + g_log_set_always_fatal (always_fatal_mask); + + g_assert_true (ot_keyfile_copy_group (g_keyfile, tmp, section)); + + g_auto(GStrv) keys = g_key_file_get_keys (g_keyfile, section, &length, NULL); + g_strfreev (g_key_file_get_keys (tmp, section, &length2, NULL)); + g_assert_cmpint(length, ==, length2); + + for (gsize ii = 0; ii < length; ii++) + { + g_autofree char *value = g_key_file_get_value (g_keyfile, section, keys[ii], NULL); + g_autofree char *value2 = g_key_file_get_value (g_keyfile, section, keys[ii], NULL); + g_assert_cmpstr (value, ==, value2); + } + +} + +static void +fill_keyfile (GKeyFile *file) +{ + g_key_file_set_boolean (file, "section", "a_boolean_true", TRUE); + g_key_file_set_boolean (file, "section", "a_boolean_false", FALSE); + + g_key_file_set_value (file, "section", "value_foo", "foo"); + g_key_file_set_value (file, "section", "value_bar", "bar"); +} + +int main (int argc, char **argv) +{ + int ret; + g_test_init (&argc, &argv, NULL); + g_keyfile = g_key_file_new (); + fill_keyfile (g_keyfile); + + g_test_add_func ("/keyfile-utils/get-boolean-with-default", test_get_boolean_with_default); + g_test_add_func ("/keyfile-utils/get-value-with-default", test_get_value_with_default); + g_test_add_func ("/keyfile-utils/get-value-with-default-group-optional", test_get_value_with_default_group_optional); + g_test_add_func ("/keyfile-utils/copy-group", test_copy_group); + + ret = g_test_run(); + + g_key_file_free (g_keyfile); + + return ret; +} diff --git a/tests/test-libarchive-import.c b/tests/test-libarchive-import.c new file mode 100644 index 0000000..d3429cd --- /dev/null +++ b/tests/test-libarchive-import.c @@ -0,0 +1,625 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include + +#include +#include "ostree-libarchive-private.h" +#include +#include + +typedef struct { + OstreeRepo *repo; + int fd; + int fd_empty; + char *tmpd; + GError *skip_all; +} TestData; + +static void +test_data_init (TestData *td) +{ + GError *error = NULL; + g_autoptr(OtAutoArchiveWrite) a = archive_write_new (); + struct archive_entry *ae; + uid_t uid = getuid (); + gid_t gid = getgid (); + + td->tmpd = g_mkdtemp (g_strdup ("/var/tmp/test-libarchive-import-XXXXXX")); + g_assert_cmpint (0, ==, chdir (td->tmpd)); + + td->fd = openat (AT_FDCWD, "foo.tar.gz", O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0644); + (void) unlink ("foo.tar.gz"); + + g_assert_no_error (error); + g_assert (td->fd >= 0); + + g_assert_cmpint (0, ==, archive_write_set_format_pax (a)); + g_assert_cmpint (0, ==, archive_write_add_filter_gzip (a)); + g_assert_cmpint (0, ==, archive_write_open_fd (a, td->fd)); + + ae = archive_entry_new (); + archive_entry_set_pathname (ae, "/"); + archive_entry_set_mode (ae, S_IFDIR | 0755); + archive_entry_set_uid (ae, uid); + archive_entry_set_gid (ae, gid); + g_assert_cmpint (0, ==, archive_write_header (a, ae)); + archive_entry_free (ae); + + ae = archive_entry_new (); + archive_entry_set_pathname (ae, "/file"); + archive_entry_set_mode (ae, S_IFREG | 0777); + archive_entry_set_uid (ae, uid); + archive_entry_set_gid (ae, gid); + archive_entry_set_size (ae, 4); + g_assert_cmpint (0, ==, archive_write_header (a, ae)); + g_assert_cmpint (4, ==, archive_write_data (a, "foo\n", 4)); + archive_entry_free (ae); + + ae = archive_entry_new (); + archive_entry_set_pathname (ae, "/devnull"); + archive_entry_set_mode (ae, S_IFCHR | 0777); + archive_entry_set_uid (ae, uid); + archive_entry_set_gid (ae, gid); + archive_entry_set_devmajor (ae, 1); + archive_entry_set_devminor (ae, 3); + g_assert_cmpint (0, ==, archive_write_header (a, ae)); + archive_entry_free (ae); + + ae = archive_entry_new (); + archive_entry_set_pathname (ae, "/anotherfile"); + archive_entry_set_mode (ae, S_IFREG | 0777); + archive_entry_set_uid (ae, uid); + archive_entry_set_gid (ae, gid); + archive_entry_set_size (ae, 4); + g_assert_cmpint (0, ==, archive_write_header (a, ae)); + g_assert_cmpint (4, ==, archive_write_data (a, "bar\n", 4)); + archive_entry_free (ae); + + ae = archive_entry_new (); + archive_entry_set_pathname (ae, "/etc"); + archive_entry_set_mode (ae, S_IFDIR | 0755); + archive_entry_set_uid (ae, uid); + archive_entry_set_gid (ae, gid); + g_assert_cmpint (0, ==, archive_write_header (a, ae)); + archive_entry_free (ae); + + ae = archive_entry_new (); + archive_entry_set_pathname (ae, "/etc/file"); + archive_entry_set_mode (ae, S_IFREG | 0777); + archive_entry_set_uid (ae, uid); + archive_entry_set_gid (ae, gid); + archive_entry_set_size (ae, 4); + g_assert_cmpint (0, ==, archive_write_header (a, ae)); + g_assert_cmpint (4, ==, archive_write_data (a, "bar\n", 4)); + archive_entry_free (ae); + + g_assert_cmpint (ARCHIVE_OK, ==, archive_write_close (a)); + + td->fd_empty = openat (AT_FDCWD, "empty.tar.gz", O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0644); + g_assert (td->fd_empty >= 0); + (void) unlink ("empty.tar.gz"); + + g_assert_cmpint (ARCHIVE_OK, ==, archive_write_free (a)); + a = archive_write_new (); + g_assert (a); + + g_assert_cmpint (0, ==, archive_write_set_format_pax (a)); + g_assert_cmpint (0, ==, archive_write_add_filter_gzip (a)); + g_assert_cmpint (0, ==, archive_write_open_fd (a, td->fd_empty)); + g_assert_cmpint (ARCHIVE_OK, ==, archive_write_close (a)); + + { g_autoptr(GFile) repopath = g_file_new_for_path ("repo"); + td->repo = ostree_repo_new (repopath); + + g_assert_cmpint (0, ==, mkdir ("repo", 0755)); + + ostree_repo_create (td->repo, OSTREE_REPO_MODE_BARE_USER, NULL, &error); + + /* G_IO_ERROR_NOT_SUPPORTED probably means no extended attribute support */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) + g_propagate_prefixed_error (&td->skip_all, g_steal_pointer (&error), + "Unable to set up repository: "); + else + g_assert_no_error (error); + } +} + +static gboolean +spawn_cmdline (const char *cmd, GError **error) +{ + int estatus; + if (!g_spawn_command_line_sync (cmd, NULL, NULL, &estatus, error)) + return FALSE; + if (!g_spawn_check_exit_status (estatus, error)) + return FALSE; + return TRUE; +} + +static void +test_archive_setup (int fd, struct archive *a) +{ + g_assert_cmpint (0, ==, lseek (fd, 0, SEEK_SET)); + g_assert_cmpint (0, ==, archive_read_support_format_all (a)); + g_assert_cmpint (0, ==, archive_read_support_filter_all (a)); + g_assert_cmpint (0, ==, archive_read_open_fd (a, fd, 8192)); +} + +static void +test_libarchive_noautocreate_empty (gconstpointer data) +{ + TestData *td = (void*)data; + GError *error = NULL; + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + OstreeRepoImportArchiveOptions opts = { 0, }; + glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + return; + } + + test_archive_setup (td->fd_empty, a); + + (void)ostree_repo_import_archive_to_mtree (td->repo, &opts, a, mtree, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ostree_mutable_tree_get_metadata_checksum (mtree) == NULL); +} + +static void +test_libarchive_autocreate_empty (gconstpointer data) +{ + TestData *td = (void*)data; + g_autoptr(GError) error = NULL; + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + OstreeRepoImportArchiveOptions opts = { 0, }; + glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + return; + } + + opts.autocreate_parents = 1; + + test_archive_setup (td->fd_empty, a); + + (void)ostree_repo_import_archive_to_mtree (td->repo, &opts, a, mtree, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ostree_mutable_tree_get_metadata_checksum (mtree) != NULL); +} + +static void +test_libarchive_error_device_file (gconstpointer data) +{ + TestData *td = (void*)data; + g_autoptr(GError) error = NULL; + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + OstreeRepoImportArchiveOptions opts = { 0, }; + glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + return; + } + + test_archive_setup (td->fd, a); + + (void)ostree_repo_import_archive_to_mtree (td->repo, &opts, a, mtree, NULL, NULL, &error); + g_assert (error != NULL); + g_clear_error (&error); +} + +static gboolean +skip_if_no_xattr (TestData *td) +{ + /* /var/tmp might actually be a tmpfs */ + if (setxattr (td->tmpd, "user.test-xattr-support", "yes", 4, 0) != 0) + { + int saved_errno = errno; + g_autofree gchar *message + = g_strdup_printf ("unable to setxattr on \"%s\": %s", + td->tmpd, g_strerror (saved_errno)); + g_test_skip (message); + return TRUE; + } + + return FALSE; +} + +static gboolean +import_write_and_ref (OstreeRepo *repo, + OstreeRepoImportArchiveOptions *opts, + struct archive *a, + const char *ref, + OstreeRepoCommitModifier *modifier, + GError **error) +{ + g_autoptr(OstreeMutableTree) mtree = ostree_mutable_tree_new (); + + if (!ostree_repo_prepare_transaction (repo, NULL, NULL, error)) + return FALSE; + + if (!ostree_repo_import_archive_to_mtree (repo, opts, a, mtree, modifier, + NULL, error)) + return FALSE; + + g_autoptr(GFile) root = NULL; + if (!ostree_repo_write_mtree (repo, mtree, &root, NULL, error)) + return FALSE; + + g_autofree char *commit_checksum = NULL; + if (!ostree_repo_write_commit (repo, NULL, "", "", NULL, + OSTREE_REPO_FILE (root), + &commit_checksum, NULL, error)) + return FALSE; + + ostree_repo_transaction_set_ref (repo, NULL, ref, commit_checksum); + + if (!ostree_repo_commit_transaction (repo, NULL, NULL, error)) + return FALSE; + + return TRUE; +} + +static void +test_libarchive_ignore_device_file (gconstpointer data) +{ + TestData *td = (void*)data; + g_autoptr(GError) error = NULL; + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + OstreeRepoImportArchiveOptions opts = { 0, }; + + if (skip_if_no_xattr (td)) + goto out; + + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + + test_archive_setup (td->fd, a); + + opts.ignore_unsupported_content = TRUE; + + if (!import_write_and_ref (td->repo, &opts, a, "foo", NULL, &error)) + goto out; + + /* check contents */ + if (!spawn_cmdline ("ostree --repo=repo ls foo file", &error)) + goto out; + + if (!spawn_cmdline ("ostree --repo=repo ls foo anotherfile", &error)) + goto out; + + if (!spawn_cmdline ("ostree --repo=repo ls foo /etc/file", &error)) + goto out; + + if (spawn_cmdline ("ostree --repo=repo ls foo devnull", &error)) + g_assert_not_reached (); + g_assert (error != NULL); + g_clear_error (&error); + + out: + g_assert_no_error (error); +} + +static gboolean +check_ostree_convention (GError *error) +{ + if (!spawn_cmdline ("ostree --repo=repo ls bar file", &error)) + return FALSE; + + if (!spawn_cmdline ("ostree --repo=repo ls bar anotherfile", &error)) + return FALSE; + + if (!spawn_cmdline ("ostree --repo=repo ls bar /usr/etc/file", &error)) + return FALSE; + + if (spawn_cmdline ("ostree --repo=repo ls bar /etc/file", &error)) + g_assert_not_reached (); + g_assert (error != NULL); + g_clear_error (&error); + + if (spawn_cmdline ("ostree --repo=repo ls bar devnull", &error)) + g_assert_not_reached (); + g_assert (error != NULL); + g_clear_error (&error); + + return TRUE; +} + +static void +test_libarchive_ostree_convention (gconstpointer data) +{ + TestData *td = (void*)data; + GError *error = NULL; + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + OstreeRepoImportArchiveOptions opts = { 0, }; + + if (skip_if_no_xattr (td)) + goto out; + + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + + test_archive_setup (td->fd, a); + + opts.autocreate_parents = TRUE; + opts.use_ostree_convention = TRUE; + opts.ignore_unsupported_content = TRUE; + + if (!import_write_and_ref (td->repo, &opts, a, "bar", NULL, &error)) + goto out; + + if (!check_ostree_convention (error)) + goto out; + + out: + g_assert_no_error (error); +} + +static GVariant* +xattr_cb (OstreeRepo *repo, + const char *path, + GFileInfo *file_info, + gpointer user_data) +{ + g_auto(GVariantBuilder) builder; + g_variant_builder_init (&builder, (GVariantType*)"a(ayay)"); + if (strcmp (path, "/anotherfile") == 0) + g_variant_builder_add (&builder, "(@ay@ay)", + g_variant_new_bytestring ("user.data"), + g_variant_new_bytestring ("mydata")); + return g_variant_ref_sink (g_variant_builder_end (&builder)); +} + +static void +test_libarchive_xattr_callback (gconstpointer data) +{ + TestData *td = (void*)data; + GError *error = NULL; + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + OstreeRepoImportArchiveOptions opts = { 0 }; + g_autoptr(OstreeRepoCommitModifier) modifier = NULL; + char buf[7] = { 0 }; + + if (skip_if_no_xattr (td)) + goto out; + + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + + modifier = ostree_repo_commit_modifier_new (0, NULL, NULL, NULL); + ostree_repo_commit_modifier_set_xattr_callback (modifier, xattr_cb, + NULL, NULL); + + test_archive_setup (td->fd, a); + + opts.ignore_unsupported_content = TRUE; + + if (!import_write_and_ref (td->repo, &opts, a, "baz", modifier, &error)) + goto out; + + /* check contents */ + if (!spawn_cmdline ("ostree --repo=repo checkout baz baz-checkout", &error)) + goto out; + + g_assert_cmpint (0, >, getxattr ("baz-checkout/file", "user.data", NULL, 0)); + g_assert_cmpint (ENODATA, ==, errno); + + if (getxattr ("baz-checkout/anotherfile", "user.data", buf, sizeof buf) < 0) + { + glnx_set_prefix_error_from_errno (&error, "%s", "getxattr"); + goto out; + } + + g_assert_cmpstr (buf, ==, "mydata"); + + out: + g_assert_no_error (error); +} + +static GVariant* +path_cb (OstreeRepo *repo, + const char *path, + GFileInfo *file_info, + gpointer user_data) +{ + if (strcmp (path, "/etc/file") == 0) + *(gboolean*)user_data = TRUE; + return NULL; +} + +static void +entry_pathname_test_helper (gconstpointer data, gboolean on) +{ + TestData *td = (void*)data; GError *error = NULL; + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + OstreeRepoImportArchiveOptions opts = { 0, }; + OstreeRepoCommitModifier *modifier = NULL; + gboolean met_etc_file = FALSE; + + if (skip_if_no_xattr (td)) + goto out; + + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + + modifier = ostree_repo_commit_modifier_new (0, NULL, NULL, NULL); + ostree_repo_commit_modifier_set_xattr_callback (modifier, path_cb, + NULL, &met_etc_file); + + test_archive_setup (td->fd, a); + + opts.autocreate_parents = TRUE; + opts.use_ostree_convention = TRUE; + opts.ignore_unsupported_content = TRUE; + opts.callback_with_entry_pathname = on; + + if (!import_write_and_ref (td->repo, &opts, a, "bar", modifier, &error)) + goto out; + + /* the flag shouldn't have any effect on the final tree */ + if (!check_ostree_convention (error)) + goto out; + + if (!on && met_etc_file) + { + g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Received callback with /etc/file"); + goto out; + } + + if (on && !met_etc_file) + { + g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Did not receive callback with /etc/file"); + goto out; + } + + ostree_repo_commit_modifier_unref (modifier); + out: + g_assert_no_error (error); +} + +static void +test_libarchive_no_use_entry_pathname (gconstpointer data) +{ + entry_pathname_test_helper (data, FALSE); +} + +static void +test_libarchive_use_entry_pathname (gconstpointer data) +{ + entry_pathname_test_helper (data, TRUE); +} + +static void +test_libarchive_selinux (gconstpointer data) +{ + TestData *td = (void*)data; + GError *error = NULL; + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + OstreeRepoImportArchiveOptions opts = { 0 }; + glnx_unref_object OstreeSePolicy *sepol = NULL; + g_autoptr(OstreeRepoCommitModifier) modifier = NULL; + char buf[64] = { 0 }; + + if (skip_if_no_xattr (td)) + goto out; + if (getenv ("container")) + { + // FIXME dedup this with libtest.sh have_selinux_relabel + g_test_skip ("skip in containers for now"); + goto out; + } + + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + + { + glnx_unref_object GFile *root = g_file_new_for_path ("/"); + + sepol = ostree_sepolicy_new (root, NULL, NULL); + } + + if (sepol == NULL || ostree_sepolicy_get_name (sepol) == NULL) + { + g_test_skip ("SELinux disabled"); + goto out; + } + + modifier = ostree_repo_commit_modifier_new (0, NULL, NULL, NULL); + ostree_repo_commit_modifier_set_sepolicy (modifier, sepol); + + test_archive_setup (td->fd, a); + + opts.ignore_unsupported_content = TRUE; + + if (!import_write_and_ref (td->repo, &opts, a, "bob", modifier, &error)) + goto out; + + /* check contents */ + if (!spawn_cmdline ("ostree --repo=repo checkout bob bob-checkout", &error)) + goto out; + + if (getxattr ("bob-checkout/etc", "security.selinux", buf, sizeof buf) < 0) + { + glnx_set_prefix_error_from_errno (&error, "%s", "getxattr"); + goto out; + } + + buf[(sizeof buf) - 1] = '\0'; + g_assert_cmpstr (buf, ==, "system_u:object_r:etc_t:s0"); + + out: + g_assert_no_error (error); +} + +int main (int argc, char **argv) +{ + TestData td = {NULL,}; + int r; + + test_data_init (&td); + + g_test_init (&argc, &argv, NULL); + + g_test_add_data_func ("/libarchive/noautocreate-empty", &td, test_libarchive_noautocreate_empty); + g_test_add_data_func ("/libarchive/autocreate-empty", &td, test_libarchive_autocreate_empty); + g_test_add_data_func ("/libarchive/error-device-file", &td, test_libarchive_error_device_file); + g_test_add_data_func ("/libarchive/ignore-device-file", &td, test_libarchive_ignore_device_file); + g_test_add_data_func ("/libarchive/ostree-convention", &td, test_libarchive_ostree_convention); + g_test_add_data_func ("/libarchive/xattr-callback", &td, test_libarchive_xattr_callback); + g_test_add_data_func ("/libarchive/no-use-entry-pathname", &td, test_libarchive_no_use_entry_pathname); + g_test_add_data_func ("/libarchive/use-entry-pathname", &td, test_libarchive_use_entry_pathname); + g_test_add_data_func ("/libarchive/selinux", &td, test_libarchive_selinux); + + r = g_test_run(); + + g_clear_object (&td.repo); + if (td.tmpd && g_getenv ("TEST_SKIP_CLEANUP") == NULL) + (void) glnx_shutil_rm_rf_at (AT_FDCWD, td.tmpd, NULL, NULL); + g_free (td.tmpd); + return r; +} diff --git a/tests/test-libarchive.sh b/tests/test-libarchive.sh new file mode 100755 index 0000000..174be80 --- /dev/null +++ b/tests/test-libarchive.sh @@ -0,0 +1,250 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +if ! ostree --version | grep -q -e '- libarchive'; then + echo "1..0 #SKIP no libarchive support compiled in" + exit 0 +fi + +. $(dirname $0)/libtest.sh + +echo "1..18" + +setup_test_repository "bare" + +cd ${test_tmpdir} +mkdir foo +cd foo +mkdir -p usr/bin usr/lib +echo contents > usr/bin/foo +touch usr/bin/foo0 +ln usr/bin/foo usr/bin/bar +ln usr/bin/foo0 usr/bin/bar0 +ln -s foo usr/bin/sl +mkdir -p usr/local/bin +ln usr/bin/foo usr/local/bin/baz +ln usr/bin/foo0 usr/local/bin/baz0 +ln usr/bin/sl usr/local/bin/slhl +touch usr/bin/setuidme +touch usr/bin/skipme +echo "a library" > usr/lib/libfoo.so +echo "another library" > usr/lib/libbar.so + +# Create a tar archive +tar -c -z -f ../foo.tar.gz . +# Create a cpio archive +find . | cpio -o -H newc > ../foo.cpio + +cd .. + +cat > statoverride.txt < skiplist.txt < files1/testfile +echo "not overwritten" > files1/otherfile +echo "overwriting file" > files2/testfile +ln -s "to-be-overwritten-symlink" files1/testsymlink +ln -s "overwriting-symlink" files2/testsymlink +ln -s "not overwriting symlink" files2/ohersymlink +echo "original" > files1/subdir/original +echo "new" > files2/subdir/new + +tar -c -C files1 -z -f files1.tar.gz . +tar -c -C files2 -z -f files2.tar.gz . + +$OSTREE commit -s 'multi tar' -b multicommit --tree=tar=files1.tar.gz --tree=tar=files2.tar.gz +echo "ok tar multicommit" + +cd ${test_tmpdir} +$OSTREE checkout multicommit multicommit-checkout +cd multicommit-checkout +assert_file_has_content testfile "overwriting file" +assert_file_has_content otherfile "not overwritten" +assert_file_has_content subdir/original "original" +assert_file_has_content subdir/new "new" +echo "ok tar multicommit contents" + +cd ${test_tmpdir}/multicommit-files +tar -c -C files1 -z -f partial.tar.gz subdir/original +$OSTREE commit -s 'partial' -b partial --tar-autocreate-parents --tree=tar=partial.tar.gz +echo "ok tar partial commit" + +cd ${test_tmpdir} +$OSTREE checkout partial partial-checkout +cd partial-checkout +assert_file_has_content subdir/original "original" +echo "ok tar partial commit contents" + +uid=$(id -u) +gid=$(id -g) +autocreate_args="--tar-autocreate-parents --owner-uid=${uid} --owner-gid=${gid}" + +cd ${test_tmpdir} +tar -cf empty.tar.gz -T /dev/null +$OSTREE commit -b tar-empty ${autocreate_args} --tree=tar=empty.tar.gz +$OSTREE ls tar-empty > ls.txt +assert_file_has_content ls.txt "d00755 ${uid} ${gid} 0 /" +echo "ok tar autocreate with owner uid/gid" + +# noop pathname filter +cd ${test_tmpdir} +$OSTREE commit -b test-tar ${autocreate_args} \ + --tar-pathname-filter='^nosuchfile/,nootherfile/' \ + --statoverride=statoverride.txt \ + --skip-list=skiplist.txt \ + --tree=tar=foo.tar.gz +rm test-tar-co -rf +$OSTREE checkout test-tar test-tar-co +assert_valid_content ${test_tmpdir}/test-tar-co +echo "ok tar pathname filter prefix (noop)" + +# Add a prefix +cd ${test_tmpdir} +# Update the metadata overrides matching our pathname filter +for f in statoverride.txt skiplist.txt; do + sed -i -e 's,/usr/,/foo/usr/,' $f +done +$OSTREE commit -b test-tar ${autocreate_args} \ + --tar-pathname-filter='^,foo/' \ + --statoverride=statoverride.txt \ + --skip-list=skiplist.txt \ + --tree=tar=foo.tar.gz +rm test-tar-co -rf +$OSTREE checkout test-tar test-tar-co +assert_has_dir test-tar-co/foo +assert_valid_content ${test_tmpdir}/test-tar-co/foo +echo "ok tar pathname filter prefix" + +# Test anchored and not-anchored +for filter in '^usr/bin/,usr/sbin/' '/bin/,/sbin/'; do + cd ${test_tmpdir} + $OSTREE commit -b test-tar ${autocreate_args} \ + --tar-pathname-filter=$filter \ + --tree=tar=foo.tar.gz + rm test-tar-co -rf + $OSTREE checkout test-tar test-tar-co + cd test-tar-co + # Check that we just had usr/bin → usr/sbin + assert_not_has_file usr/bin/foo + assert_file_has_content usr/sbin/foo contents + assert_not_has_file usr/sbin/libfoo.so + assert_file_has_content usr/lib/libfoo.so 'a library' + echo "ok tar pathname filter modification: ${filter}" +done + +# Test sizes metadata. This needs an archive repo, so a separate repo is used. +cd ${test_tmpdir} +rm -rf repo2 +ostree_repo_init repo2 --mode=archive +${CMD_PREFIX} ostree --repo=repo2 commit \ + -s "from tar" -b test-tar \ + --generate-sizes \ + --tree=tar=foo.tar.gz +${CMD_PREFIX} ostree --repo=repo2 show --print-sizes test-tar > sizes.txt +assert_file_has_content sizes.txt 'Compressed size (needed/total): 0[  ]bytes/1.1[  ]kB' +assert_file_has_content sizes.txt 'Unpacked size (needed/total): 0[  ]bytes/900[  ]bytes' +assert_file_has_content sizes.txt 'Number of objects (needed/total): 0/12' +echo "ok tar sizes metadata" diff --git a/tests/test-local-pull-depth.sh b/tests/test-local-pull-depth.sh new file mode 100755 index 0000000..96b20b9 --- /dev/null +++ b/tests/test-local-pull-depth.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# Copyright (C) 2015 Dan Nicholson +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_test_repository "archive" + +echo "1..1" + +cd ${test_tmpdir} +mkdir repo2 +ostree_repo_init repo2 --mode="archive" + +${CMD_PREFIX} ostree --repo=repo2 pull-local repo +find repo2/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^1$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^0$" + +${CMD_PREFIX} ostree --repo=repo2 pull-local --depth=0 repo +find repo2/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^1$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^0$" + +${CMD_PREFIX} ostree --repo=repo2 pull-local --depth=1 --commit-metadata-only repo +find repo2/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^2$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^1$" + +${CMD_PREFIX} ostree --repo=repo2 pull-local --depth=1 repo +find repo2/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^2$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^0$" + +${CMD_PREFIX} ostree --repo=repo2 pull-local --depth=-1 repo +find repo2/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^2$" +find repo2/state -name '*.commitpartial' | wc -l > commitpartialcount +assert_file_has_content commitpartialcount "^0$" + +echo "ok local pull depth" diff --git a/tests/test-local-pull.sh b/tests/test-local-pull.sh new file mode 100755 index 0000000..555e9b2 --- /dev/null +++ b/tests/test-local-pull.sh @@ -0,0 +1,117 @@ +#!/bin/bash +# +# Copyright (C) 2014 Alexander Larsson +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +# We don't want OSTREE_GPG_HOME used for these tests. +unset OSTREE_GPG_HOME + +. $(dirname $0)/libtest.sh + +skip_without_user_xattrs + +echo "1..8" + +setup_test_repository "archive" +echo "ok setup" + +cd ${test_tmpdir} +mkdir repo2 +ostree_repo_init repo2 --mode="bare-user" + +${CMD_PREFIX} ostree --repo=repo2 pull-local repo +${CMD_PREFIX} ostree --repo=repo2 fsck +echo "ok pull-local z2 to bare-user" + +mkdir repo3 +ostree_repo_init repo3 --mode="archive" +${CMD_PREFIX} ostree --repo=repo3 pull-local repo2 +${CMD_PREFIX} ostree --repo=repo3 fsck +echo "ok pull-local bare-user to z2" + + +# Verify the name + size + mode + type + symlink target + owner/group are the same +# for all checkouts +${CMD_PREFIX} ostree checkout --repo repo test2 checkout1 +find checkout1 -printf '%P %s %#m %u/%g %y %l\n' | sort > checkout1.files + +${CMD_PREFIX} ostree checkout --repo repo2 test2 checkout2 +find checkout2 -printf '%P %s %#m %u/%g %y %l\n' | sort > checkout2.files + +${CMD_PREFIX} ostree checkout --repo repo3 test2 checkout3 +find checkout3 -printf '%P %s %#m %u/%g %y %l\n' | sort > checkout3.files + +cmp checkout1.files checkout2.files +cmp checkout1.files checkout3.files +echo "ok checkouts same" + +if has_gpgme; then + # These tests are needed GPG support + mkdir repo4 + ostree_repo_init repo4 --mode="archive" + ${CMD_PREFIX} ostree --repo=repo4 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo + + if ${CMD_PREFIX} ostree --repo=repo4 pull-local --remote=origin --gpg-verify repo test2 2>&1; then + assert_not_reached "GPG verification unexpectedly succeeded" + fi + echo "ok --gpg-verify with no signature" + + ${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME} test2 ${TEST_GPG_KEYID_1} + + mkdir repo5 + ostree_repo_init repo5 --mode="archive" + ${CMD_PREFIX} ostree --repo=repo5 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo + ${CMD_PREFIX} ostree --repo=repo5 pull-local --remote=origin --gpg-verify repo test2 + echo "ok --gpg-verify" + + mkdir repo6 + ostree_repo_init repo6 --mode="archive" + ${CMD_PREFIX} ostree --repo=repo6 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo + if ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1; then + assert_not_reached "GPG summary verification with no summary unexpectedly succeeded" + fi + + ${OSTREE} summary --update + + if ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1; then + assert_not_reached "GPG summary verification with signed no summary unexpectedly succeeded" + fi + + ${OSTREE} summary --update --gpg-sign=${TEST_GPG_KEYID_1} --gpg-homedir=${TEST_GPG_KEYHOME} + + ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1 + + echo "ok --gpg-verify-summary" +else + echo "ok --gpg-verify with no signature | # SKIP due GPG unavailability" + echo "ok --gpg-verify | # SKIP due GPG unavailability" + echo "ok --gpg-verify-summary | # SKIP due GPG unavailability" +fi + +mkdir repo7 +ostree_repo_init repo7 --mode="archive" +${CMD_PREFIX} ostree --repo=repo7 pull-local repo +${CMD_PREFIX} ostree --repo=repo7 fsck +for src_object in `find repo/objects -name '*.filez'`; do + dst_object=${src_object/repo/repo7} + assert_files_hardlinked "$src_object" "$dst_object" +done +echo "ok pull-local z2 to z2 default hardlink" diff --git a/tests/test-lzma.c b/tests/test-lzma.c new file mode 100644 index 0000000..c3ece96 --- /dev/null +++ b/tests/test-lzma.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include +#include "ostree-lzma-compressor.h" +#include "ostree-lzma-decompressor.h" +#include +#include + +static void +helper_test_compress_decompress (const guint8 *data, gssize data_size) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GOutputStream) out_compress = g_memory_output_stream_new_resizable (); + g_autoptr(GOutputStream) out_decompress = NULL; + g_autoptr(GInputStream) in_compress = g_memory_input_stream_new_from_data (data, data_size, NULL); + g_autoptr(GInputStream) in_decompress = NULL; + + { + gssize n_bytes_written; + g_autoptr(GInputStream) convin = NULL; + g_autoptr(GConverter) compressor = (GConverter*)_ostree_lzma_compressor_new (NULL); + convin = g_converter_input_stream_new ((GInputStream*) in_compress, compressor); + n_bytes_written = g_output_stream_splice (out_compress, convin, + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE, + NULL, &error); + g_assert_cmpint (n_bytes_written, >, 0); + g_assert_no_error (error); + } + + out_decompress = g_memory_output_stream_new_resizable (); + + { + gssize n_bytes_written; + g_autoptr(GInputStream) convin = NULL; + g_autoptr(GConverter) decompressor = (GConverter*)_ostree_lzma_decompressor_new (); + g_autoptr(GBytes) bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (out_compress)); + + in_decompress = g_memory_input_stream_new_from_bytes (bytes); + convin = g_converter_input_stream_new ((GInputStream*) in_decompress, decompressor); + n_bytes_written = g_output_stream_splice (out_decompress, convin, + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE, + NULL, &error); + g_assert_cmpint (n_bytes_written, >, 0); + g_assert_no_error (error); + } + + g_assert_cmpint (g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (out_decompress)), ==, data_size); + { + gpointer new_data = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (out_decompress)); + g_assert_cmpint (memcmp (new_data, data, data_size), ==, 0); + } + +} + +static void +test_lzma_random (void) +{ + gssize i; + guint8 buffer[4096]; + g_autoptr(GRand) r = g_rand_new (); + for (i = 0; i < sizeof(buffer); i++) + buffer[i] = g_rand_int (r); + + for (i = 2; i < (sizeof(buffer) - 1); i *= 2) + { + helper_test_compress_decompress (buffer, i - 1); + helper_test_compress_decompress (buffer, i); + helper_test_compress_decompress (buffer, i + 1); + } +} + +static void +test_lzma_big_buffer (void) +{ + const guint32 buffer_size = 1 << 21; + g_autofree guint8 *buffer = g_new (guint8, buffer_size); + + memset (buffer, (int) 'a', buffer_size); + + helper_test_compress_decompress (buffer, buffer_size); +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/lzma/random-buffer", test_lzma_random); + g_test_add_func ("/lzma/big-buffer", test_lzma_big_buffer); + + return g_test_run(); +} diff --git a/tests/test-mock-gio.c b/tests/test-mock-gio.c new file mode 100644 index 0000000..71514b0 --- /dev/null +++ b/tests/test-mock-gio.c @@ -0,0 +1,401 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "test-mock-gio.h" + +/** + * SECTION:mock-gio + * @title: Mock GIO volume interfaces + * @short_description: Mock implementations of GIO volume, mount and drive + * interfaces + * @stability: Unstable + * @include: tests/test-mock-gio.h + * + * A set of classes implementing GIO interfaces for volumes, mounts, drives + * and volume monitoring, which return mock data to the caller when used. These + * are designed for use in unit tests, to mock up removable drives when testing + * code which monitors such drives being added and removed and then queries + * properties of them. + * + * By returning mock drive locations to the caller, for example, the contents of + * a removable drive may be mocked up using temporary files. + * + * Currently, all the mock data returned by these classes to callers is static, + * set at construction time. + * + * Since: 2017.8 + */ + +/* Mock volume monitor class. This returns a static set of data to the caller, + * which it was initialised with. */ +struct _OstreeMockVolumeMonitor +{ + GVolumeMonitor parent_instance; + + GList *mounts; /* (element-type OstreeMockMount) */ + GList *volumes; /* (element-type OstreeMockVolume) */ +}; + +G_DEFINE_TYPE (OstreeMockVolumeMonitor, ostree_mock_volume_monitor, G_TYPE_VOLUME_MONITOR) + +static GList * +ostree_mock_volume_monitor_get_mounts (GVolumeMonitor *monitor) +{ + OstreeMockVolumeMonitor *self = OSTREE_MOCK_VOLUME_MONITOR (monitor); + return g_list_copy_deep (self->mounts, (GCopyFunc) g_object_ref, NULL); +} + +static GList * +ostree_mock_volume_monitor_get_volumes (GVolumeMonitor *monitor) +{ + OstreeMockVolumeMonitor *self = OSTREE_MOCK_VOLUME_MONITOR (monitor); + return g_list_copy_deep (self->volumes, (GCopyFunc) g_object_ref, NULL); +} + +static void +ostree_mock_volume_monitor_init (OstreeMockVolumeMonitor *self) +{ + /* Nothing to see here. */ +} + +static void +ostree_mock_volume_monitor_dispose (GObject *object) +{ + OstreeMockVolumeMonitor *self = OSTREE_MOCK_VOLUME_MONITOR (object); + + g_list_free_full (self->volumes, g_object_unref); + self->volumes = NULL; + + g_list_free_full (self->mounts, g_object_unref); + self->mounts = NULL; + + G_OBJECT_CLASS (ostree_mock_volume_monitor_parent_class)->dispose (object); +} + +static void +ostree_mock_volume_monitor_class_init (OstreeMockVolumeMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass); + + object_class->dispose = ostree_mock_volume_monitor_dispose; + + monitor_class->get_mounts = ostree_mock_volume_monitor_get_mounts; + monitor_class->get_volumes = ostree_mock_volume_monitor_get_volumes; +} + +/** + * ostree_mock_volume_monitor_new: + * @mounts: (element-type GMount) (transfer none): list of current #GMounts + * @volumes: (element-type GVolume) (transfer none): list of current #GVolumes + * + * Create a new mock #GVolumeMonitor which will return the given static lists of + * #GMounts and #GVolumes to any caller of g_volume_monitor_get_mounts() or + * g_volume_monitor_get_volumes(). + * + * Typically, the elements of @mounts will be #OstreeMockMount objects and the + * elements of @volumes will be #OstreeMockVolume objects; but this does not + * have to be the case. + * + * Returns: (transfer full): a new #GVolumeMonitor object + * Since: 2017.8 + */ +GVolumeMonitor * +ostree_mock_volume_monitor_new (GList *mounts, + GList *volumes) +{ + g_autoptr(OstreeMockVolumeMonitor) monitor = NULL; + + monitor = g_object_new (OSTREE_TYPE_MOCK_VOLUME_MONITOR, NULL); + monitor->mounts = g_list_copy_deep (mounts, (GCopyFunc) g_object_ref, NULL); + monitor->volumes = g_list_copy_deep (volumes, (GCopyFunc) g_object_ref, NULL); + + return g_steal_pointer (&monitor); +} + +/* Mock volume class. This returns a static set of data to the caller, which it + * was initialised with. */ +struct _OstreeMockVolume +{ + GObject parent_instance; + + gchar *name; + GDrive *drive; /* (owned) (nullable) */ + GMount *mount; /* (owned) (nullable) */ +}; + +static void ostree_mock_volume_iface_init (GVolumeIface *iface); + +G_DEFINE_TYPE_WITH_CODE (OstreeMockVolume, ostree_mock_volume, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME, ostree_mock_volume_iface_init)) + +static gchar * +ostree_mock_volume_get_name (GVolume *volume) +{ + OstreeMockVolume *self = OSTREE_MOCK_VOLUME (volume); + return g_strdup (self->name); +} + +static GDrive * +ostree_mock_volume_get_drive (GVolume *volume) +{ + OstreeMockVolume *self = OSTREE_MOCK_VOLUME (volume); + return (self->drive != NULL) ? g_object_ref (self->drive) : NULL; +} + +static GMount * +ostree_mock_volume_get_mount (GVolume *volume) +{ + OstreeMockVolume *self = OSTREE_MOCK_VOLUME (volume); + return (self->mount != NULL) ? g_object_ref (self->mount) : NULL; +} + +static void +ostree_mock_volume_init (OstreeMockVolume *self) +{ + /* Nothing to see here. */ +} + +static void +ostree_mock_volume_dispose (GObject *object) +{ + OstreeMockVolume *self = OSTREE_MOCK_VOLUME (object); + + g_clear_pointer (&self->name, g_free); + g_clear_object (&self->drive); + g_clear_object (&self->mount); + + G_OBJECT_CLASS (ostree_mock_volume_parent_class)->dispose (object); +} + +static void +ostree_mock_volume_class_init (OstreeMockVolumeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = ostree_mock_volume_dispose; +} + +static void +ostree_mock_volume_iface_init (GVolumeIface *iface) +{ + iface->get_name = ostree_mock_volume_get_name; + iface->get_drive = ostree_mock_volume_get_drive; + iface->get_mount = ostree_mock_volume_get_mount; +} + +/** + * ostree_mock_volume_new: + * @name: volume name + * @drive: (transfer none) (nullable): drive for the volume, or %NULL if none + * should be associated + * @mount: (transfer none) (nullable): mount for the volume, or %NULL if it’s + * not mounted + * + * Create a new mock #GVolume which will return the given static @name, @drive + * and @mount to any caller of its getter methods. There is currently no + * provision for changing these values dynamically. There is also currently no + * provision for mocking the other getters of #GVolume. + * + * Typically, @drive will be an #OstreeMockDrive object and @mount will be an + * #OstreeMockMount object; but this does not have to be the case. + * + * Returns: (transfer full): a new #GVolume object + * Since: 2017.8 + */ +OstreeMockVolume * +ostree_mock_volume_new (const gchar *name, + GDrive *drive, + GMount *mount) +{ + g_autoptr(OstreeMockVolume) volume = NULL; + + volume = g_object_new (OSTREE_TYPE_MOCK_VOLUME, NULL); + volume->name = g_strdup (name); + volume->drive = (drive != NULL) ? g_object_ref (drive) : NULL; + volume->mount = (mount != NULL) ? g_object_ref (mount) : NULL; + + return g_steal_pointer (&volume); +} + +/* Mock drive class. This returns a static set of data to the caller, which it + * was initialised with. */ +struct _OstreeMockDrive +{ + GObject parent_instance; + + gboolean is_removable; +}; + +static void ostree_mock_drive_iface_init (GDriveIface *iface); + +G_DEFINE_TYPE_WITH_CODE (OstreeMockDrive, ostree_mock_drive, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_DRIVE, ostree_mock_drive_iface_init)) + +#if GLIB_CHECK_VERSION(2, 50, 0) +static gboolean +ostree_mock_drive_is_removable (GDrive *drive) +{ + OstreeMockDrive *self = OSTREE_MOCK_DRIVE (drive); + return self->is_removable; +} +#endif + +static void +ostree_mock_drive_init (OstreeMockDrive *self) +{ + /* Nothing to see here. */ +} + +static void +ostree_mock_drive_class_init (OstreeMockDriveClass *klass) +{ + /* Nothing to see here. */ +} + +static void +ostree_mock_drive_iface_init (GDriveIface *iface) +{ +#if GLIB_CHECK_VERSION(2, 50, 0) + iface->is_removable = ostree_mock_drive_is_removable; +#endif +} + +/** + * ostree_mock_drive_new: + * @is_removable: %TRUE if the drive is removable; %FALSE otherwise + * + * Create a new mock #GDrive which will return the given static @is_removable to + * any caller of its getter methods. There is currently no provision for mocking + * the other getters of #GDrive. + * + * Returns: (transfer full): a new #GDrive object + * Since: 2017.8 + */ +OstreeMockDrive * +ostree_mock_drive_new (gboolean is_removable) +{ + g_autoptr(OstreeMockDrive) drive = NULL; + + drive = g_object_new (OSTREE_TYPE_MOCK_DRIVE, NULL); + drive->is_removable = is_removable; + + return g_steal_pointer (&drive); +} + +/* Mock mount class. This returns a static set of data to the caller, which it + * was initialised with. */ +struct _OstreeMockMount +{ + GObject parent_instance; + + gchar *name; /* (owned) */ + GFile *root; /* (owned) */ +}; + +static void ostree_mock_mount_iface_init (GMountIface *iface); + +G_DEFINE_TYPE_WITH_CODE (OstreeMockMount, ostree_mock_mount, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT, ostree_mock_mount_iface_init)) + +static gchar * +ostree_mock_mount_get_name (GMount *mount) +{ + OstreeMockMount *self = OSTREE_MOCK_MOUNT (mount); + return g_strdup (self->name); +} + +static GFile * +ostree_mock_mount_get_root (GMount *mount) +{ + OstreeMockMount *self = OSTREE_MOCK_MOUNT (mount); + return g_object_ref (self->root); +} + +static void +ostree_mock_mount_init (OstreeMockMount *self) +{ + /* Nothing to see here. */ +} + +static void +ostree_mock_mount_dispose (GObject *object) +{ + OstreeMockMount *self = OSTREE_MOCK_MOUNT (object); + + g_clear_pointer (&self->name, g_free); + g_clear_object (&self->root); + + G_OBJECT_CLASS (ostree_mock_mount_parent_class)->dispose (object); +} + +static void +ostree_mock_mount_class_init (OstreeMockMountClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = ostree_mock_mount_dispose; +} + +static void +ostree_mock_mount_iface_init (GMountIface *iface) +{ + iface->get_name = ostree_mock_mount_get_name; + iface->get_root = ostree_mock_mount_get_root; +} + +/** + * ostree_mock_mount_new: + * @name: mount name + * @root: (transfer none): root path for the mounted file system + * + * Create a new mock #GMount which will return the given static @name and @root + * to any caller of its getter methods. There is currently no provision for + * mocking the other getters of #GMount. + * + * Typically, @root will point to a temporary directory where a mocked file + * system is present; but this does not have to be the case. + * + * Returns: (transfer full): a new #GMount object + * Since: 2017.8 + */ +OstreeMockMount * +ostree_mock_mount_new (const gchar *name, + GFile *root) +{ + g_autoptr(OstreeMockMount) mount = NULL; + + mount = g_object_new (OSTREE_TYPE_MOCK_MOUNT, NULL); + mount->name = g_strdup (name); + mount->root = g_object_ref (root); + + return g_steal_pointer (&mount); +} diff --git a/tests/test-mock-gio.h b/tests/test-mock-gio.h new file mode 100644 index 0000000..a96eca2 --- /dev/null +++ b/tests/test-mock-gio.h @@ -0,0 +1,128 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include +#include + +#include "ostree-types.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_MOCK_VOLUME_MONITOR (ostree_mock_volume_monitor_get_type ()) + +/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44): +G_GNUC_INTERNAL +G_DECLARE_FINAL_TYPE (OstreeMockVolumeMonitor, ostree_mock_volume_monitor, OSTREE, MOCK_VOLUME_MONITOR, GVolumeMonitor) */ + +G_GNUC_INTERNAL +GType ostree_mock_volume_monitor_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeMockVolumeMonitor OstreeMockVolumeMonitor; +typedef struct { GVolumeMonitorClass parent_class; } OstreeMockVolumeMonitorClass; + +static inline OstreeMockVolumeMonitor *OSTREE_MOCK_VOLUME_MONITOR (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_mock_volume_monitor_get_type (), OstreeMockVolumeMonitor); } +static inline gboolean OSTREE_IS_MOCK_VOLUME_MONITOR (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_mock_volume_monitor_get_type ()); } +G_GNUC_END_IGNORE_DEPRECATIONS + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeMockVolumeMonitor, g_object_unref) + +G_GNUC_INTERNAL +GVolumeMonitor *ostree_mock_volume_monitor_new (GList *mounts, + GList *volumes); + +#define OSTREE_TYPE_MOCK_VOLUME (ostree_mock_volume_get_type ()) + +/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44): +G_GNUC_INTERNAL +G_DECLARE_FINAL_TYPE (OstreeMockVolume, ostree_mock_volume, OSTREE, MOCK_VOLUME, GObject) */ + +G_GNUC_INTERNAL +GType ostree_mock_volume_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeMockVolume OstreeMockVolume; +typedef struct { GObjectClass parent_class; } OstreeMockVolumeClass; + +static inline OstreeMockVolume *OSTREE_MOCK_VOLUME (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_mock_volume_get_type (), OstreeMockVolume); } +static inline gboolean OSTREE_IS_MOCK_VOLUME (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_mock_volume_get_type ()); } +G_GNUC_END_IGNORE_DEPRECATIONS + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeMockVolume, g_object_unref) + +G_GNUC_INTERNAL +OstreeMockVolume *ostree_mock_volume_new (const gchar *name, + GDrive *drive, + GMount *mount); + +#define OSTREE_TYPE_MOCK_DRIVE (ostree_mock_drive_get_type ()) + +/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44): +G_GNUC_INTERNAL +G_DECLARE_FINAL_TYPE (OstreeMockDrive, ostree_mock_drive, OSTREE, MOCK_DRIVE, GObject) */ + +G_GNUC_INTERNAL +GType ostree_mock_drive_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeMockDrive OstreeMockDrive; +typedef struct { GObjectClass parent_class; } OstreeMockDriveClass; + +static inline OstreeMockDrive *OSTREE_MOCK_DRIVE (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_mock_drive_get_type (), OstreeMockDrive); } +static inline gboolean OSTREE_IS_MOCK_DRIVE (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_mock_drive_get_type ()); } +G_GNUC_END_IGNORE_DEPRECATIONS + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeMockDrive, g_object_unref) + +G_GNUC_INTERNAL +OstreeMockDrive *ostree_mock_drive_new (gboolean is_removable); + +#define OSTREE_TYPE_MOCK_MOUNT (ostree_mock_mount_get_type ()) + +/* Manually expanded version of the following, omitting autoptr support (for GLib < 2.44): +G_GNUC_INTERNAL +G_DECLARE_FINAL_TYPE (OstreeMockMount, ostree_mock_mount, OSTREE, MOCK_MOUNT, GObject) */ + +G_GNUC_INTERNAL +GType ostree_mock_mount_get_type (void); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +typedef struct _OstreeMockMount OstreeMockMount; +typedef struct { GObjectClass parent_class; } OstreeMockMountClass; + +static inline OstreeMockMount *OSTREE_MOCK_MOUNT (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_CAST (ptr, ostree_mock_mount_get_type (), OstreeMockMount); } +static inline gboolean OSTREE_IS_MOCK_MOUNT (gpointer ptr) { return G_TYPE_CHECK_INSTANCE_TYPE (ptr, ostree_mock_mount_get_type ()); } +G_GNUC_END_IGNORE_DEPRECATIONS + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeMockMount, g_object_unref) + +G_GNUC_INTERNAL +OstreeMockMount *ostree_mock_mount_new (const gchar *name, + GFile *root); + +G_END_DECLS diff --git a/tests/test-mutable-tree.c b/tests/test-mutable-tree.c new file mode 100644 index 0000000..d0dfdd7 --- /dev/null +++ b/tests/test-mutable-tree.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include "ostree-mutable-tree.h" +#include +#include +#include +#include +#include "ot-unix-utils.h" + +static void +test_metadata_checksum (void) +{ + g_autoptr(GError) error = NULL; + const char *checksum = "12345678901234567890123456789012"; + glnx_unref_object OstreeMutableTree *tree = ostree_mutable_tree_new (); + + g_assert_null (ostree_mutable_tree_get_metadata_checksum (tree)); + + ostree_mutable_tree_set_metadata_checksum (tree, checksum); + + g_assert_cmpstr (checksum, ==, ostree_mutable_tree_get_metadata_checksum (tree)); + + /* If a child tree's metadata changes the parent tree's contents needs to be + * recalculated */ + glnx_unref_object OstreeMutableTree *subdir = NULL; + g_assert (ostree_mutable_tree_ensure_dir (tree, "subdir", &subdir, &error)); + g_assert_nonnull (subdir); + + ostree_mutable_tree_set_contents_checksum ( + subdir, "11111111111111111111111111111111"); + ostree_mutable_tree_set_metadata_checksum ( + subdir, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + ostree_mutable_tree_set_contents_checksum ( + tree, "abcdefabcdefabcdefabcdefabcdefab"); + + g_assert_cmpstr (ostree_mutable_tree_get_contents_checksum (tree), ==, + "abcdefabcdefabcdefabcdefabcdefab"); + ostree_mutable_tree_set_metadata_checksum ( + subdir, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); + g_assert_null (ostree_mutable_tree_get_contents_checksum (tree)); + g_assert_cmpstr (ostree_mutable_tree_get_contents_checksum (subdir), ==, + "11111111111111111111111111111111"); +} + +static void +test_mutable_tree_walk (void) +{ + glnx_unref_object OstreeMutableTree *tree = ostree_mutable_tree_new (); + glnx_unref_object OstreeMutableTree *parent = NULL; + g_autoptr(GPtrArray) split_path = NULL; + GError *error = NULL; + const char *pathname = "a/b/c/d/e/f/g/i"; + const char *checksum = "01234567890123456789012345678901"; + + g_assert (ot_util_path_split_validate (pathname, &split_path, &error)); + + g_assert (ostree_mutable_tree_ensure_parent_dirs (tree, split_path, + checksum, &parent, + &error)); + { + glnx_unref_object OstreeMutableTree *subdir = NULL; + g_assert (ostree_mutable_tree_walk (tree, split_path, 0, &subdir, &error)); + g_assert_nonnull (subdir); + } + + { + glnx_unref_object OstreeMutableTree *subdir = NULL; + g_assert_false (ostree_mutable_tree_walk (tree, split_path, 1, &subdir, &error)); + g_assert_null (subdir); + g_clear_error (&error); + } + + { + glnx_unref_object OstreeMutableTree *subdir = NULL; + glnx_unref_object OstreeMutableTree *a = NULL; + g_autofree char *source_checksum = NULL; + g_assert (ostree_mutable_tree_lookup (tree, "a", &source_checksum, &a, &error)); + g_assert_no_error (error); + g_assert (ostree_mutable_tree_walk (a, split_path, 1, &subdir, &error)); + g_assert_no_error (error); + g_assert (subdir); + } +} + +static void +test_ensure_parent_dirs (void) +{ + glnx_unref_object OstreeMutableTree *tree = ostree_mutable_tree_new (); + glnx_unref_object OstreeMutableTree *parent = NULL; + g_autoptr(GPtrArray) split_path = NULL; + g_autoptr(GError) error = NULL; + const char *pathname = "/foo/bar/baz"; + const char *checksum = "01234567890123456789012345678901"; + g_autofree char *source_checksum = NULL; + glnx_unref_object OstreeMutableTree *source_subdir = NULL; + g_autofree char *source_checksum2 = NULL; + glnx_unref_object OstreeMutableTree *source_subdir2 = NULL; + + g_assert (ot_util_path_split_validate (pathname, &split_path, &error)); + + g_assert (ostree_mutable_tree_ensure_parent_dirs (tree, split_path, + checksum, &parent, + &error)); + + g_assert (ostree_mutable_tree_lookup (tree, "foo", &source_checksum, + &source_subdir, &error)); + + g_assert_false (ostree_mutable_tree_lookup (tree, "bar", &source_checksum2, + &source_subdir2, &error)); + g_clear_error (&error); +} + +static void +test_ensure_dir (void) +{ + glnx_unref_object OstreeMutableTree *tree = ostree_mutable_tree_new (); + glnx_unref_object OstreeMutableTree *parent = NULL; + g_autoptr(GError) error = NULL; + const char *dirname = "foo"; + const char *filename = "bar"; + const char *checksum = "01234567890123456789012345678901"; + g_autofree char *source_checksum = NULL; + glnx_unref_object OstreeMutableTree *source_subdir = NULL; + + g_assert (ostree_mutable_tree_ensure_dir (tree, dirname, &parent, &error)); + g_assert (ostree_mutable_tree_lookup (tree, dirname, &source_checksum, &source_subdir, &error)); + + g_assert (ostree_mutable_tree_replace_file (tree, filename, checksum, &error)); + g_assert_false (ostree_mutable_tree_ensure_dir (tree, filename, &parent, &error)); + g_clear_error (&error); +} + +static void +test_replace_file (void) +{ + glnx_unref_object OstreeMutableTree *tree = ostree_mutable_tree_new (); + g_autoptr(GError) error = NULL; + const char *filename = "bar"; + const char *checksum = "01234567890123456789012345678901"; + const char *checksum2 = "ABCDEF01234567890123456789012345"; + + g_assert (ostree_mutable_tree_replace_file (tree, filename, checksum, &error)); + { + g_autofree char *out_checksum = NULL; + glnx_unref_object OstreeMutableTree *subdir = NULL; + g_assert (ostree_mutable_tree_lookup (tree, filename, &out_checksum, &subdir, &error)); + g_assert_cmpstr (checksum, ==, out_checksum); + } + + g_assert (ostree_mutable_tree_replace_file (tree, filename, checksum2, &error)); + { + g_autofree char *out_checksum = NULL; + glnx_unref_object OstreeMutableTree *subdir = NULL; + g_assert (ostree_mutable_tree_lookup (tree, filename, &out_checksum, &subdir, &error)); + g_assert_cmpstr (checksum2, ==, out_checksum); + } +} + +static void +test_contents_checksum (void) +{ + const char *checksum = "01234567890123456789012345678901"; + const char *subdir_checksum = "ABCD0123456789012345678901234567"; + glnx_unref_object OstreeMutableTree *tree = ostree_mutable_tree_new (); + glnx_unref_object OstreeMutableTree *subdir = NULL; + g_assert_null (ostree_mutable_tree_get_contents_checksum (tree)); + + ostree_mutable_tree_set_contents_checksum (tree, checksum); + g_assert_cmpstr (checksum, ==, ostree_mutable_tree_get_contents_checksum (tree)); + + g_assert (ostree_mutable_tree_ensure_dir (tree, "subdir", &subdir, NULL)); + g_assert_nonnull (subdir); + + ostree_mutable_tree_set_contents_checksum (subdir, subdir_checksum); + g_assert_cmpstr (subdir_checksum, ==, ostree_mutable_tree_get_contents_checksum (subdir)); + g_assert_null (ostree_mutable_tree_get_contents_checksum (tree)); +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/mutable-tree/metadata-checksum", test_metadata_checksum); + g_test_add_func ("/mutable-tree/contents-checksum", test_contents_checksum); + g_test_add_func ("/mutable-tree/parent-dirs", test_ensure_parent_dirs); + g_test_add_func ("/mutable-tree/walk", test_mutable_tree_walk); + g_test_add_func ("/mutable-tree/ensure-dir", test_ensure_dir); + g_test_add_func ("/mutable-tree/replace-file", test_replace_file); + return g_test_run(); +} diff --git a/tests/test-no-initramfs.sh b/tests/test-no-initramfs.sh new file mode 100755 index 0000000..22846c8 --- /dev/null +++ b/tests/test-no-initramfs.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +. $(dirname $0)/libtest.sh + +echo "1..10" + +setup_os_repository "archive-z2" "uboot" + +cd ${test_tmpdir} + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=rootfs --os=testos testos:testos/buildmaster/x86_64-runtime + +assert_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'root=LABEL=rootfs' +assert_not_file_has_content sysroot/boot/loader/entries/ostree-1-testos.conf 'init=' + +echo "ok deployment with initramfs" + +pull_test_tree() { + kernel_contents=$1 + initramfs_contents=$2 + devicetree_contents=$3 + + printf "TEST SETUP:\n kernel: %s\n initramfs: %s\n devicetree: %s\n layout: %s\n" \ + "$kernel_contents" "$initramfs_contents" "$devicetree_contents" "$layout" + + rm -rf ${test_tmpdir}/osdata/usr/lib/modules/3.6.0/{initramfs.img,vmlinuz,devicetree} \ + ${test_tmpdir}/osdata/usr/lib/ostree-boot \ + ${test_tmpdir}/osdata/boot + if [ "$layout" = "/usr/lib/modules" ]; then + # Fedora compatible layout + cd ${test_tmpdir}/osdata/usr/lib/modules/3.6.0 + echo -n "$kernel_contents" > vmlinuz + [ -n "$initramfs_contents" ] && echo -n "$initramfs_contents" > initramfs.img + [ -n "$devicetree_contents" ] && echo -n "$devicetree_contents" > devicetree + elif [ "$layout" = "/usr/lib/ostree-boot" ] || [ "$layout" = "/boot" ]; then + # "Legacy" layout + mkdir -p "${test_tmpdir}/osdata/$layout" + cd "${test_tmpdir}/osdata/$layout" + bootcsum=$(echo -n "$kernel_contents$initramfs_contents$devicetree_contents" \ + | sha256sum | cut -f 1 -d ' ') + echo -n "$kernel_contents" > vmlinuz-${bootcsum} + [ -n "$initramfs_contents" ] && echo -n "$initramfs_contents" > initramfs-${bootcsum} + [ -n "$devicetree_contents" ] && echo -n "$devicetree_contents" > devicetree-${bootcsum} + else + exit 1 + fi + cd - + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --tree=dir=osdata/ -b testos/buildmaster/x86_64-runtime + ${CMD_PREFIX} ostree pull testos:testos/buildmaster/x86_64-runtime +} + +get_key_from_bootloader_conf() { + conffile=$1 + key=$2 + + assert_file_has_content "$conffile" "^$key" + awk "/^$key/ { print \$2 }" "$conffile" +} + +for layout in /usr/lib/modules /usr/lib/ostree-boot /boot; +do + pull_test_tree "the kernel only" + ${CMD_PREFIX} ostree admin deploy --os=testos --karg=root=/dev/sda2 --karg=rootwait testos:testos/buildmaster/x86_64-runtime + assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'rootwait' + assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'init=' + assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'initrd' + + echo "ok switching to bootdir with no initramfs layout=$layout" + + pull_test_tree "the kernel" "initramfs to assist the kernel" + ${CMD_PREFIX} ostree admin deploy --os=testos --karg-none --karg=root=LABEL=rootfs testos:testos/buildmaster/x86_64-runtime + assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'initrd' + assert_file_has_content sysroot/boot/$(get_key_from_bootloader_conf sysroot/boot/loader/entries/ostree-2-testos.conf "initrd") "initramfs to assist the kernel" + assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'root=LABEL=rootfs' + assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'rootwait' + assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'init=' + + echo "ok switching from no initramfs to initramfs enabled sysroot layout=$layout" + + pull_test_tree "the kernel" "" "my .dtb file" + ${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime + + assert_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'init=' + assert_file_has_content sysroot/boot/"$(get_key_from_bootloader_conf sysroot/boot/loader/entries/ostree-2-testos.conf 'devicetree')" "my \.dtb file" + assert_not_file_has_content sysroot/boot/loader/entries/ostree-2-testos.conf 'initrd' + + echo "ok switching from initramfs to no initramfs sysroot with devicetree layout=$layout" +done diff --git a/tests/test-oldstyle-partial.sh b/tests/test-oldstyle-partial.sh new file mode 100755 index 0000000..24bbdd4 --- /dev/null +++ b/tests/test-oldstyle-partial.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Copyright (C) 2015 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +echo '1..1' + +cd ${test_tmpdir} +rm repo -rf +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +${CMD_PREFIX} ostree --repo=repo pull origin main --subpath /baz +${CMD_PREFIX} ostree fsck --repo=repo >fsck.out +assert_file_has_content fsck.out 'Verifying content integrity of 0 commit objects' +assert_file_has_content fsck.out '1 partial commits not verified' + +echo "ok" diff --git a/tests/test-ot-opt-utils.c b/tests/test-ot-opt-utils.c new file mode 100644 index 0000000..6b01e93 --- /dev/null +++ b/tests/test-ot-opt-utils.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "ostree-mutable-tree.h" +#include +#include +#include +#include +#include "ot-opt-utils.h" +#include "libglnx.h" + +static GString *printerr_str = NULL; + +static void +util_usage_error_printerr (const gchar *string) +{ + if (printerr_str == NULL) + printerr_str = g_string_new (NULL); + g_string_append (printerr_str, string); +} + +static void +test_ot_util_usage_error (void) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GOptionContext) context = g_option_context_new ("[TEST]"); + GPrintFunc old_printerr = g_set_printerr_handler (util_usage_error_printerr); + + ot_util_usage_error (context, "find_me", &error); + + g_assert_nonnull (strstr (printerr_str->str, "[TEST]")); + g_assert_nonnull (strstr (error->message, "find_me")); + g_clear_error (&error); + + g_set_printerr_handler (old_printerr); + g_string_free (printerr_str, TRUE); + printerr_str = NULL; +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/ot-opt-utils/ot-util-usage-error", test_ot_util_usage_error); + return g_test_run(); +} diff --git a/tests/test-ot-tool-util.c b/tests/test-ot-tool-util.c new file mode 100644 index 0000000..82b8da6 --- /dev/null +++ b/tests/test-ot-tool-util.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include "ostree-mutable-tree.h" +#include +#include +#include +#include +#include "ot-tool-util.h" + +/* + + +gboolean +ot_parse_boolean (const char *value, + gboolean *out_parsed, + GError **error); +gboolean +ot_parse_keyvalue (const char *keyvalue, + char **out_key, + char **out_value, + GError **error); +*/ +static void +test_ot_parse_boolean (void) +{ + g_autoptr(GError) error = NULL; + gboolean out = FALSE; + g_assert_true (ot_parse_boolean ("yes", &out, &error)); + g_assert_true (out); + + out = FALSE; + g_assert_true (ot_parse_boolean ("1", &out, &error)); + g_assert_true (out); + + out = FALSE; + g_assert_true (ot_parse_boolean ("true", &out, &error)); + g_assert_true (out); + + g_assert_true (ot_parse_boolean ("false", &out, &error)); + g_assert_false (out); + + out = TRUE; + g_assert_true (ot_parse_boolean ("no", &out, &error)); + g_assert_false (out); + + out = TRUE; + g_assert_true (ot_parse_boolean ("0", &out, &error)); + g_assert_false (out); + + out = TRUE; + g_assert_true (ot_parse_boolean ("none", &out, &error)); + g_assert_false (out); + g_clear_error (&error); + + g_assert_false (ot_parse_boolean ("FOO", &out, &error)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); +} + +static void +test_ot_parse_keyvalue (void) +{ + g_autoptr(GError) error = NULL; + char *keyvalue[] = {"foo=bar", "a=", "b=1231231"}; + char *key[] = {"foo", "a", "b"}; + char *value[] = {"bar", "", "1231231"}; + guint i; + + for (i = 0; i < G_N_ELEMENTS (keyvalue); i++) + { + g_autofree char *out_key = NULL; + g_autofree char *out_value = NULL; + g_assert_true (ot_parse_keyvalue (keyvalue[i], + &out_key, + &out_value, + &error)); + g_assert_cmpstr (out_key, ==, key[i]); + g_assert_cmpstr (out_value, ==, value[i]); + } + + { + g_autofree char *out_key = NULL; + g_autofree char *out_value = NULL; + g_assert_false (ot_parse_keyvalue ("blabla", + &out_key, + &out_value, + &error)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_clear_error (&error); + } +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/ot-tool-util/parse-boolean", test_ot_parse_boolean); + g_test_add_func ("/ot-tool-util/parse-keyvalue", test_ot_parse_keyvalue); + return g_test_run(); +} diff --git a/tests/test-ot-unix-utils.c b/tests/test-ot-unix-utils.c new file mode 100644 index 0000000..3847100 --- /dev/null +++ b/tests/test-ot-unix-utils.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libglnx.h" +#include "ot-unix-utils.h" +#include + +static void +test_ot_util_path_split_validate (void) +{ + const char *paths[] = {"foo/bar", "test", "foo/bar:", "a/b/c/d/e/f/g/h/i/l/m/n/o/p", NULL}; + int n_components[] = {2, 1, 2, 14, 0}; + int i; + for (i = 0; paths[i]; i++) + { + GError *error = NULL; + g_autoptr(GPtrArray) components = NULL; + if (! ot_util_path_split_validate (paths[i], &components, &error)) + { + int j; + g_assert_cmpint (components->len, ==, n_components[i]); + for (j = 0; j < components->len; j++) + { + g_assert (strcmp (components->pdata[i], "..")); + g_assert_null (strchr (components->pdata[i], '/')); + } + } + } +} + +static void +test_ot_util_filename_validate (void) +{ + g_autoptr(GError) error = NULL; + + /* Check for valid inputs. */ + g_assert (ot_util_filename_validate ("valid", &error)); + g_assert_no_error (error); + g_assert (ot_util_filename_validate ("valid_file_name", &error)); + g_assert_no_error (error); + g_assert (ot_util_filename_validate ("file.name", &error)); + g_assert_no_error (error); + g_assert (ot_util_filename_validate ("foo..", &error)); + g_assert_no_error (error); + g_assert (ot_util_filename_validate ("..bar", &error)); + g_assert_no_error (error); + g_assert (ot_util_filename_validate ("baz:", &error)); + g_assert_no_error (error); + + /* Check for invalid inputs. */ + g_assert_false (ot_util_filename_validate ("not/valid/file/name", &error)); + g_clear_error (&error); + g_assert_false (ot_util_filename_validate (".", &error)); + g_clear_error (&error); + g_assert_false (ot_util_filename_validate ("..", &error)); + g_clear_error (&error); +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/ot_util_path_split_validate", test_ot_util_path_split_validate); + g_test_add_func ("/ot_util_filename_validate", test_ot_util_filename_validate); + return g_test_run(); +} diff --git a/tests/test-parent.sh b/tests/test-parent.sh new file mode 100755 index 0000000..b62b955 --- /dev/null +++ b/tests/test-parent.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Copyright (C) 2016 Alexander Larsson +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_user_xattrs + +skip_without_gpgme + +echo '1..2' + +setup_test_repository "archive" + +export OSTREE_GPG_SIGN="${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME}" + +cd ${test_tmpdir} + +# Create a repo +ostree_repo_init repo2 +${CMD_PREFIX} ostree --repo=repo2 remote add --gpg-import=${test_tmpdir}/gpghome/trusted/pubring.gpg --set=gpg-verify=true aremote file://$(pwd)/repo test2 + +# Create a repo with repo2 as parent +${CMD_PREFIX} ostree init --repo=repo3 --mode=bare-user +${CMD_PREFIX} ostree config --repo=repo3 set core.parent `pwd`/repo2 + +# Ensure the unsigned pull fails so we know we imported the gpg config correctly +if ${CMD_PREFIX} ostree --repo=repo3 pull aremote; then + assert_not_reached "GPG verification unexpectedly succeeded" +fi +echo "ok unsigned pull w/parent" + +# Make a signed commit and ensure we can now pull +${OSTREE} commit -b test2 -s "A GPG signed commit" -m "Signed commit body" --gpg-sign=${TEST_GPG_KEYID_1} --gpg-homedir=${TEST_GPG_KEYHOME} --tree=dir=files +${CMD_PREFIX} ostree --repo=repo3 pull aremote + +echo "ok signed pull w/parent" diff --git a/tests/test-pre-signed-pull.sh b/tests/test-pre-signed-pull.sh new file mode 100755 index 0000000..20f2b59 --- /dev/null +++ b/tests/test-pre-signed-pull.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# +# Copyright (C) 2020 Collabora Ltd. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..1" + +if ! has_sign_ed25519; then + echo "ok pre-signed pull # SKIP due ed25519 unavailability" + exit 0 +fi + +mkdir upstream +cd upstream +tar xzf $(dirname $0)/pre-signed-pull-data.tar.gz +cd .. + +pubkey='45yzbkuEok0lLabxzdAHWUDSMZgYfxU40sN+LMfYHVA=' + +ostree --repo=repo init --mode=archive +ostree --repo=repo remote add upstream --set=gpg-verify=false --sign-verify=ed25519=inline:${pubkey} file://$(pwd)/upstream/repo +ostree --repo=repo pull upstream:testref + +wrongkey=$(gen_ed25519_random_public) +rm repo -rf +ostree --repo=repo init --mode=archive +ostree --repo=repo remote add badupstream --set=gpg-verify=false --sign-verify=ed25519=inline:${wrongkey} file://$(pwd)/upstream/repo +if ostree --repo=repo pull badupstream:testref 2>err.txt; then + fatal "pulled with wrong key" +fi +assert_file_has_content err.txt 'error:.* ed25519: Signature couldn.t be verified with: key' +echo "ok pre-signed pull" diff --git a/tests/test-prune-collections.sh b/tests/test-prune-collections.sh new file mode 100755 index 0000000..e034bd9 --- /dev/null +++ b/tests/test-prune-collections.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..2' + +cd ${test_tmpdir} + +# Check that refs with collection IDs (i.e. refs in refs/mirrors) are taken into account +# when computing reachability of objects while pruning. +set_up_repo() { + rm -rf repo files + + mkdir repo + ostree_repo_init repo + + mkdir files + pushd files + ${CMD_PREFIX} ostree --repo=../repo commit -s "Commit 1" -b original-ref > ../original-ref-checksum + popd + ${CMD_PREFIX} ostree --repo=repo refs --collections --create=org.example.Collection:some-ref $(cat original-ref-checksum) +} + +set_up_repo + +# Try deleting a specific commit which is still pointed to by both refs. +if ${CMD_PREFIX} ostree --repo=repo prune --delete-commit=$(cat original-ref-checksum) 2>/dev/null; then + assert_not_reached "prune unexpectedly succeeded in deleting a referenced commit!" +fi + +# Pruning normally should do nothing. +${CMD_PREFIX} ostree --repo=repo prune --refs-only > prune +assert_file_has_content prune "^Total objects: 3$" +assert_file_has_content prune "^No unreachable objects$" + +# Remove the original-ref so that only the some-ref with a collection ID points to the commit. +${CMD_PREFIX} ostree --repo=repo refs --delete original-ref + +${CMD_PREFIX} ostree --repo=repo prune --refs-only > prune +assert_file_has_content prune "^Total objects: 3$" +assert_file_has_content prune "^No unreachable objects$" + +# Remove the second ref so that the commit is now orphaned. +${CMD_PREFIX} ostree --repo=repo refs --collections --delete org.example.Collection + +${CMD_PREFIX} ostree --repo=repo prune --refs-only > prune +assert_file_has_content prune "^Total objects: 3$" +assert_file_has_content prune "^Deleted 3 objects, [0-9]\+ bytes freed$" + +echo "ok 1 prune-collections" + +# Try again, but in an old repository where refs/mirrors doesn’t exist to begin with. +set_up_repo +rm -rf repo/refs/mirrors + +${CMD_PREFIX} ostree --repo=repo prune --refs-only > prune +assert_file_has_content prune "^Total objects: 3$" +assert_file_has_content prune "^No unreachable objects$" + +echo "ok 2 prune-collections in old repository" diff --git a/tests/test-prune.sh b/tests/test-prune.sh new file mode 100755 index 0000000..e873480 --- /dev/null +++ b/tests/test-prune.sh @@ -0,0 +1,298 @@ +#!/bin/bash +# +# Copyright (C) 2015 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_user_xattrs + +setup_fake_remote_repo1 "archive" + +echo '1..12' + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +mkdir -p tree/root +touch tree/root/a + +# Add a few commits +seq 5 | while read; do + echo a >> tree/root/a + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit --branch=test -m test -s test tree +done + + +${CMD_PREFIX} ostree --repo=repo pull --depth=-1 origin test + +assert_repo_has_n_commits() { + repo=$1 + count=$2 + assert_streq "$(find ${repo}/objects -name '*.commit' | wc -l)" "${count}" +} + +# Test --no-prune +objectcount_orig=$(find repo/objects | wc -l) +${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=0 --no-prune | tee noprune.txt +assert_file_has_content noprune.txt 'Would delete: [1-9][0-9]* objects, freeing [1-9][0-9]*' +objectcount_new=$(find repo/objects | wc -l) +assert_streq "${objectcount_orig}" "${objectcount_new}" + +${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=2 -v +assert_repo_has_n_commits repo 3 +find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount +assert_file_has_content tombstonecommitcount "^0$" +$OSTREE fsck + +${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=1 -v +assert_repo_has_n_commits repo 2 +find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount +assert_file_has_content tombstonecommitcount "^0$" + +${CMD_PREFIX} ostree --repo=repo fsck --add-tombstones +find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount +assert_file_has_content repo/config "tombstone-commits=true" +assert_file_has_content tombstonecommitcount "^1$" + +# pull once again and use tombstone commits +${CMD_PREFIX} ostree --repo=repo pull --depth=-1 origin test + +${CMD_PREFIX} ostree --repo=repo fsck --add-tombstones +find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount +assert_file_has_content tombstonecommitcount "^0$" + +${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=0 -v +assert_repo_has_n_commits repo 1 +find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount +assert_not_file_has_content tombstonecommitcount "^0$" +$OSTREE fsck + +# and that tombstone are deleted once the commits are pulled again +${CMD_PREFIX} ostree --repo=repo pull --depth=-1 origin test +find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount +assert_file_has_content tombstonecommitcount "^0$" + +COMMIT_TO_DELETE=$(${CMD_PREFIX} ostree --repo=repo log test | grep ^commit | cut -f 2 -d' ' | tail -n 1) +${CMD_PREFIX} ostree --repo=repo prune --delete-commit=$COMMIT_TO_DELETE +find repo/objects -name '*.tombstone-commit' | wc -l > tombstonecommitcount +assert_file_has_content tombstonecommitcount "^1$" +$OSTREE fsck + +${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=0 -v +assert_repo_has_n_commits repo 1 +${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="2005-10-29 12:43:29 +0000" +${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="2010-10-29 12:43:29 +0000" +assert_repo_has_n_commits repo 3 +${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="2015-10-29 12:43:29 +0000" +assert_repo_has_n_commits repo 2 +$OSTREE fsck + + +${CMD_PREFIX} ostree prune --repo=repo --refs-only --depth=0 -v +assert_repo_has_n_commits repo 2 +${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="October 25 1985" +${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="October 21 2015" +assert_repo_has_n_commits repo 4 +${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="1 week ago" +assert_repo_has_n_commits repo 2 + +${CMD_PREFIX} ostree --repo=repo commit --branch=oldcommit tree --timestamp="2005-10-29 12:43:29 +0000" +oldcommit_rev=$($OSTREE --repo=repo rev-parse oldcommit) +$OSTREE ls ${oldcommit_rev} +${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="1 week ago" +$OSTREE ls ${oldcommit_rev} +$OSTREE fsck + +${CMD_PREFIX} ostree --repo=repo pull --depth=-1 origin test +${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="November 05 1955" +${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="October 25 1985" +${CMD_PREFIX} ostree --repo=repo commit --branch=test -m test -s test tree --timestamp="October 21 2015" + +${CMD_PREFIX} ostree --repo=repo static-delta generate test^ +${CMD_PREFIX} ostree --repo=repo static-delta generate test +${CMD_PREFIX} ostree --repo=repo static-delta list | wc -l > deltascount +assert_file_has_content deltascount "^2$" +COMMIT_TO_DELETE=$(${CMD_PREFIX} ostree --repo=repo rev-parse test) +${CMD_PREFIX} ostree --repo=repo prune --static-deltas-only --delete-commit=$COMMIT_TO_DELETE +${CMD_PREFIX} ostree --repo=repo fsck +${CMD_PREFIX} ostree --repo=repo static-delta list | wc -l > deltascount +assert_file_has_content deltascount "^1$" +${CMD_PREFIX} ostree --repo=repo static-delta generate test +${CMD_PREFIX} ostree --repo=repo static-delta list | wc -l > deltascount +assert_file_has_content deltascount "^2$" +if ${CMD_PREFIX} ostree --repo=repo prune --static-deltas-only --keep-younger-than="October 20 2015" 2>err.txt; then + fatal "pruned deltas only" +fi +assert_file_has_content_literal err.txt "--static-deltas-only requires --delete-commit" + +echo "ok prune" + +rm repo -rf +ostree_repo_init repo --mode=bare-user +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo pull --depth=-1 --commit-metadata-only origin test +${CMD_PREFIX} ostree --repo=repo prune + +echo "ok prune with partial repo" + +assert_has_n_objects() { + find $1/objects -name '*.filez' | wc -l > object-count + assert_file_has_content object-count $2 + rm object-count +} + +cd ${test_tmpdir} +for repo in repo child-repo tmp-repo; do + rm ${repo} -rf + ostree_repo_init ${repo} --mode=archive +done +echo parent=${test_tmpdir}/repo >> child-repo/config +mkdir files +for x in $(seq 3); do + echo afile${x} > files/afile${x} +done +${CMD_PREFIX} ostree --repo=repo commit -b test files +assert_has_n_objects repo 3 +# Inherit 1-3, add 4-6 +for x in $(seq 4 6); do + echo afile${x} > files/afile${x} +done +# Commit into a temp repo, then do a local pull, which triggers +# the parent repo lookup for dedup +${CMD_PREFIX} ostree --repo=tmp-repo commit -b childtest files +${CMD_PREFIX} ostree --repo=child-repo pull-local tmp-repo childtest +assert_has_n_objects child-repo 3 +# Sanity check prune doesn't do anything +for repo in repo child-repo; do ${CMD_PREFIX} ostree --repo=${repo} prune; done +# Now, leave orphaned objects in the parent only pointed to by the child +${CMD_PREFIX} ostree --repo=repo refs --delete test +${CMD_PREFIX} ostree --repo=child-repo prune --refs-only --depth=0 +assert_has_n_objects child-repo 3 + +echo "ok prune with parent repo" + +# Delete all the above since I can't be bothered to think about how new tests +# would interact. We make a new repo test suite, then clone it +# for "subtests" below with reinitialize_datesnap_repo() +rm repo datetest-snapshot-repo -rf +ostree_repo_init datetest-snapshot-repo --mode=archive +# Some ancient commits on the both a stable/dev branch +for day in $(seq 5); do + ${CMD_PREFIX} ostree --repo=datetest-snapshot-repo commit --branch=stable -m test -s "old stable build $day" tree --timestamp="October $day 1985" + ${CMD_PREFIX} ostree --repo=datetest-snapshot-repo commit --branch=dev -m test -s "old dev build $day" tree --timestamp="October $day 1985" +done +# And some new ones +for x in $(seq 3); do + ${CMD_PREFIX} ostree --repo=datetest-snapshot-repo commit --branch=stable -m test -s "new stable build $x" tree + ${CMD_PREFIX} ostree --repo=datetest-snapshot-repo commit --branch=dev -m test -s "new dev build $x" tree +done +assert_repo_has_n_commits datetest-snapshot-repo 16 + +# Snapshot the above +reinitialize_datesnap_repo() { + rm repo -rf + ostree_repo_init repo --mode=archive + ${CMD_PREFIX} ostree --repo=repo pull-local --depth=-1 datetest-snapshot-repo +} + +# This test prunes with both younger than as well as a full strong ref to the +# stable branch +reinitialize_datesnap_repo +# First, a quick test of invalid input +if ${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="1 week ago" --retain-branch-depth=stable=BACON 2>err.txt; then + assert_not_reached "BACON is a number?!" +fi +assert_file_has_content err.txt 'Invalid depth BACON' +${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="1 week ago" --retain-branch-depth=stable=-1 +assert_repo_has_n_commits repo 11 +# Double check our backup is unchanged +assert_repo_has_n_commits datetest-snapshot-repo 16 +$OSTREE fsck + +# Again but this time only retain 6 (5+1) commits on stable. This should drop +# out 8 - 6 = 2 commits (so the 11 above minus 2 = 9) +${CMD_PREFIX} ostree --repo=repo prune --keep-younger-than="1 week ago" --retain-branch-depth=stable=5 +assert_repo_has_n_commits repo 9 +$OSTREE fsck +echo "ok retain branch depth and keep-younger-than" + +# Just stable branch ref, we should prune everything except the tip of dev, +# so 8 stable + 1 dev = 9 +reinitialize_datesnap_repo +${CMD_PREFIX} ostree --repo=repo prune --depth=0 --retain-branch-depth=stable=-1 +assert_repo_has_n_commits repo 9 +$OSTREE fsck + +echo "ok retain branch depth (alone)" + +# Test --only-branch with --depth=0; this should be exactly identical to the +# above with a result of 9. +reinitialize_datesnap_repo +${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --depth=0 +assert_repo_has_n_commits repo 9 +$OSTREE fsck +echo "ok --only-branch --depth=0" + +# Test --only-branch with --depth=1; should just add 1 to the above, for 10. +reinitialize_datesnap_repo +${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --depth=1 +assert_repo_has_n_commits repo 10 +echo "ok --only-branch --depth=1" + +# Test --only-branch with all branches +reinitialize_datesnap_repo +${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --only-branch=stable --depth=0 +assert_repo_has_n_commits repo 2 +reinitialize_datesnap_repo +${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --only-branch=stable --depth=1 +assert_repo_has_n_commits repo 4 +echo "ok --only-branch (all) --depth=1" + +# Test --only-branch and --retain-branch-depth overlap +reinitialize_datesnap_repo +${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --only-branch=stable --depth=0 \ + --retain-branch-depth=stable=2 +assert_repo_has_n_commits repo 4 +echo "ok --only-branch and --retain-branch-depth overlap" + +# Test --only-branch and --retain-branch-depth together +reinitialize_datesnap_repo +${CMD_PREFIX} ostree --repo=repo prune --only-branch=dev --depth=0 --retain-branch-depth=stable=2 +assert_repo_has_n_commits repo 4 +echo "ok --only-branch and --retain-branch-depth together" + +# Test --only-branch with --keep-younger-than; this should be identical to the test +# above for --retain-branch-depth=stable=-1 +reinitialize_datesnap_repo +${CMD_PREFIX} ostree --repo=repo prune --only-branch=stable --keep-younger-than="1 week ago" +assert_repo_has_n_commits repo 11 +echo "ok --only-branch --keep-younger-than" + +# Test --only-branch with a nonexistent ref +reinitialize_datesnap_repo +if ${CMD_PREFIX} ostree --repo=repo prune --only-branch=BACON 2>err.txt; then + fatal "we pruned BACON?" +fi +assert_file_has_content err.txt "Refspec.*BACON.*not found" +echo "ok --only-branch=BACON" diff --git a/tests/test-pull-bare.sh b/tests/test-pull-bare.sh new file mode 100755 index 0000000..a9eaed6 --- /dev/null +++ b/tests/test-pull-bare.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +repo_mode=bare +. ${test_srcdir}/pull-test.sh diff --git a/tests/test-pull-bareuser.sh b/tests/test-pull-bareuser.sh new file mode 100755 index 0000000..6bdd304 --- /dev/null +++ b/tests/test-pull-bareuser.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_user_xattrs +setup_fake_remote_repo1 "archive" + +repo_mode=bare-user +. ${test_srcdir}/pull-test.sh diff --git a/tests/test-pull-bareuseronly.sh b/tests/test-pull-bareuseronly.sh new file mode 100755 index 0000000..a3b23d5 --- /dev/null +++ b/tests/test-pull-bareuseronly.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright (C) 2017 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_user_xattrs +setup_fake_remote_repo1 "archive" "--canonical-permissions" + +repo_mode=bare-user-only +. ${test_srcdir}/pull-test.sh diff --git a/tests/test-pull-basicauth.sh b/tests/test-pull-basicauth.sh new file mode 100755 index 0000000..4a2622a --- /dev/null +++ b/tests/test-pull-basicauth.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# +# Copyright (C) 2017 Colin Walters +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" "" "--require-basic-auth" + +echo '1..3' + +repopath=${test_tmpdir}/ostree-srv/gnomerepo +cp -a ${repopath} ${repopath}.orig + +cd ${test_tmpdir} +rm repo -rf +ostree_repo_init repo +unauthaddress=$(cat httpd-address) +badauthaddress=$(echo $unauthaddress | sed -e 's,http://,http://foo:bar@,') +goodauthaddress=$(echo $unauthaddress | sed -e 's,http://,http://foouser:barpw@,') +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin-unauth ${unauthaddress}/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin-badauth ${badauthaddress}/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin-goodauth ${goodauthaddress}/ostree/gnomerepo + +if ${CMD_PREFIX} ostree --repo=repo pull origin-unauth main 2>err.txt; then + fatal "Pulled via unauth" +fi +assert_file_has_content err.txt "401" +echo "ok unauth" +rm -f err.txt +if ${CMD_PREFIX} ostree --repo=repo pull origin-badauth main 2>err.txt; then + fatal "Pulled via badauth" +fi +assert_file_has_content err.txt "401" +rm -f err.txt +echo "ok badauth" + +${CMD_PREFIX} ostree --repo=repo pull origin-goodauth main +echo "ok basic auth" diff --git a/tests/test-pull-c.c b/tests/test-pull-c.c new file mode 100644 index 0000000..4d6cd17 --- /dev/null +++ b/tests/test-pull-c.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2016 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "libglnx.h" +#include +#include +#include +#include + +#include "libostreetest.h" + +typedef struct { + OstreeRepo *repo; +} TestData; + +static void +test_data_init (TestData *td) +{ + GError *local_error = NULL; + GError **error = &local_error; + g_autofree char *http_address = NULL; + g_autofree char *repo_url = NULL; + + td->repo = ot_test_setup_repo (NULL, error); + if (!td->repo) + goto out; + + if (!ot_test_run_libtest ("setup_fake_remote_repo1 archive", error)) + goto out; + + if (!g_file_get_contents ("httpd-address", &http_address, NULL, error)) + goto out; + + g_strstrip (http_address); + + repo_url = g_strconcat (http_address, "/ostree/gnomerepo", NULL); + + { g_autoptr(GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_autoptr(GVariant) opts = NULL; + + g_variant_builder_add (builder, "{s@v}", "gpg-verify", g_variant_new_variant (g_variant_new_boolean (FALSE))); + opts = g_variant_ref_sink (g_variant_builder_end (builder)); + + if (!ostree_repo_remote_change (td->repo, NULL, OSTREE_REPO_REMOTE_CHANGE_ADD, + "origin", repo_url, opts, NULL, error)) + goto out; + } + + out: + g_assert_no_error (local_error); +} + +static void +test_pull_multi_nochange (gconstpointer data) +{ + GError *local_error = NULL; + GError **error = &local_error; + TestData *td = (void*)data; + char *refs[] = { "main", NULL }; + + if (!ostree_repo_pull (td->repo, "origin", (char**)&refs, 0, NULL, NULL, error)) + goto out; + if (!ostree_repo_pull (td->repo, "origin", (char**)&refs, 0, NULL, NULL, error)) + goto out; + if (!ostree_repo_pull (td->repo, "origin", (char**)&refs, 0, NULL, NULL, error)) + goto out; + + out: + g_assert_no_error (local_error); +} + +static void +test_pull_multi_error_then_ok (gconstpointer data) +{ + GError *local_error = NULL; + GError **error = &local_error; + + TestData *td = (void*)data; + char *ok_refs[] = { "main", NULL }; + char *bad_refs[] = { "nosuchbranch", NULL }; + + for (guint i = 0; i < 3; i++) + { + g_autoptr(GError) tmp_error = NULL; + if (!ostree_repo_pull (td->repo, "origin", (char**)&ok_refs, 0, NULL, NULL, error)) + goto out; + if (ostree_repo_pull (td->repo, "origin", (char**)&bad_refs, 0, NULL, NULL, &tmp_error)) + g_assert_not_reached (); + g_clear_error (&tmp_error); + if (ostree_repo_pull (td->repo, "origin", (char**)&bad_refs, 0, NULL, NULL, &tmp_error)) + g_assert_not_reached (); + g_clear_error (&tmp_error); + if (!ostree_repo_pull (td->repo, "origin", (char**)&ok_refs, 0, NULL, NULL, error)) + goto out; + } + + out: + g_assert_no_error (local_error); +} + +int main (int argc, char **argv) +{ + TestData td = {NULL,}; + int r; + + test_data_init (&td); + + g_test_init (&argc, &argv, NULL); + + g_test_add_data_func ("/test-pull-c/multi-nochange", &td, test_pull_multi_nochange); + g_test_add_data_func ("/test-pull-c/multi-ok-error-repeat", &td, test_pull_multi_error_then_ok); + + r = g_test_run(); + g_clear_object (&td.repo); + + return r; +} diff --git a/tests/test-pull-collections.sh b/tests/test-pull-collections.sh new file mode 100755 index 0000000..cd60ab2 --- /dev/null +++ b/tests/test-pull-collections.sh @@ -0,0 +1,272 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..7' + +cd ${test_tmpdir} + +do_commit() { + local repo=$1 + local branch=$2 + shift 2 + + mkdir -p files + pushd files + local GPG_ARGS="" + if has_gpgme; then + GPG_ARGS="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" + fi + ${CMD_PREFIX} ostree --repo="../${repo}" commit -s "Test ${repo} commit for branch ${branch}" -b "${branch}" ${GPG_ARGS} "$@" > "../${branch}-checksum" + popd +} + +do_summary() { + local repo=$1 + shift 1 + + local GPG_ARGS="" + if has_gpgme; then + GPG_ARGS="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" + fi + ${CMD_PREFIX} ostree "--repo=${repo}" summary --update ${GPG_ARGS} +} + +do_collection_ref_show() { + local repo=$1 + local branch=$2 + shift 2 + + echo -n "collection ID: " + if ${CMD_PREFIX} ostree "--repo=${repo}" show --print-metadata-key=ostree.collection-binding $(cat "${branch}-checksum") + then : + else return 1 + fi + echo -n "refs: " + if ${CMD_PREFIX} ostree "--repo=${repo}" show --print-metadata-key=ostree.ref-binding $(cat "${branch}-checksum") + then return 0 + else return 1 + fi +} + +ensure_no_collection_ref() { + local repo=$1 + local branch=$2 + local error=$3 + shift 3 + + if do_collection_ref_show "${repo}" "${branch}" >/dev/null + then + assert_not_reached "${error}" + fi +} + +do_join() { + local IFS=', ' + echo "$*" +} + +ensure_collection_ref() { + local repo=$1 + local branch=$2 + local collection_id=$3 + shift 3 + local refs=$(do_join "$@") + + do_collection_ref_show "${repo}" "${branch}" >"${branch}-meta" + assert_file_has_content "${branch}-meta" "^collection ID: '${collection_id}'$" + assert_file_has_content "${branch}-meta" "^refs: \['${refs}'\]$" +} + +do_remote_add() { + local repo=$1 + local remote_repo=$2 + shift 2 + + local GPG_ARGS="" + if has_gpgme; then + GPG_ARGS="--gpg-import=${test_tmpdir}/gpghome/key1.asc" + fi + ${CMD_PREFIX} ostree "--repo=${repo}" remote add "${remote_repo}-remote" "file://$(pwd)/${remote_repo}" "$@" ${GPG_ARGS} +} + +do_pull() { + local repo=$1 + local remote_repo=$2 + local branch=$3 + shift 3 + + if ${CMD_PREFIX} ostree "--repo=${repo}" pull "${remote_repo}-remote" "${branch}" + then return 0 + else return 1 + fi +} + +do_local_pull() { + local repo=$1 + local remote_repo=$2 + local branch=$3 + shift 3 + + if ${CMD_PREFIX} ostree "--repo=${repo}" pull-local "${remote_repo}" "${branch}" + then return 0 + else return 1 + fi +} + +# Create a repo without the collection ID. +mkdir no-collection-repo +ostree_repo_init no-collection-repo +do_commit no-collection-repo goodncref1 +do_commit no-collection-repo sortofbadncref1 --add-metadata-string=ostree.collection-binding=org.example.Ignored +do_summary no-collection-repo +ensure_no_collection_ref \ + no-collection-repo \ + goodncref1 \ + "commits in repository without collection ID shouldn't normally contain the ostree.commit.collection metadata information" +ensure_collection_ref no-collection-repo sortofbadncref1 'org.example.Ignored' 'sortofbadncref1' + +echo "ok 1 setup remote repo without collection ID" + +# Create a repo with a collection ID. +mkdir collection-repo +ostree_repo_init collection-repo +do_commit collection-repo badcref1 # has no collection ref +# We set the repo collection ID in this hacky way to get the commit +# without the collection ID. +echo "collection-id=org.example.CollectionRepo" >>collection-repo/config +do_commit collection-repo badcref2 --add-metadata-string=ostree.collection-binding=org.example.Whatever +do_commit collection-repo badcref3 --add-metadata-string=ostree.collection-binding= +do_commit collection-repo goodcref1 +# create a badcref4 ref with a commit that has goodcref1 in its collection ref metadata +${CMD_PREFIX} ostree --repo=collection-repo refs --create=badcref4 $(cat goodcref1-checksum) +do_summary collection-repo +ensure_no_collection_ref \ + collection-repo \ + badcref1 \ + "commit in badcref1 should not have the collection ref metadata information" +ensure_collection_ref collection-repo badcref2 'org.example.Whatever' 'badcref2' +ensure_collection_ref collection-repo badcref3 '' 'badcref3' +ensure_collection_ref collection-repo goodcref1 'org.example.CollectionRepo' 'goodcref1' + +echo "ok 2 setup remote repo with collection ID" + +# Create a local repo without the collection ID. +mkdir no-collection-local-repo +ostree_repo_init no-collection-local-repo +do_commit no-collection-local-repo goodnclref1 +do_commit no-collection-local-repo sortofbadnclref1 --add-metadata-string=ostree.collection-binding=org.example.IgnoredLocal +do_summary no-collection-local-repo +ensure_no_collection_ref \ + no-collection-local-repo \ + goodnclref1 \ + "commits in repository without collection ID shouldn't normally contain the ostree.commit.collection metadata information" +ensure_collection_ref no-collection-local-repo sortofbadnclref1 'org.example.IgnoredLocal' 'sortofbadnclref1' + +echo "ok 3 setup local repo without collection ID" + +# Create a local repo with a collection ID. +mkdir collection-local-repo +ostree_repo_init collection-local-repo +do_commit collection-local-repo badclref1 # has no collection ref +# We set the repo collection ID in this hacky way to get the commit +# without the collection ID. +echo "collection-id=org.example.CollectionRepoLocal" >>collection-local-repo/config +do_commit collection-local-repo badclref2 --add-metadata-string=ostree.collection-binding=org.example.WhateverLocal +do_commit collection-local-repo badclref3 --add-metadata-string=ostree.collection-binding= +do_commit collection-local-repo goodclref1 +# create a badclref4 ref with a commit that has goodclref1 in its collection ref metadata +${CMD_PREFIX} ostree --repo=collection-local-repo refs --create=badclref4 $(cat goodclref1-checksum) +do_summary collection-local-repo +ensure_no_collection_ref \ + collection-local-repo \ + badclref1 \ + "commit in badclref1 should not have the collection ref metadata information" +ensure_collection_ref collection-local-repo badclref2 'org.example.WhateverLocal' 'badclref2' +ensure_collection_ref collection-local-repo badclref3 '' 'badclref3' +ensure_collection_ref collection-local-repo goodclref1 'org.example.CollectionRepoLocal' 'goodclref1' + +echo "ok 4 setup local repo with collection ID" + +# Create a local repository where we pull the branches from the remotes as normal, using GPG. +mkdir local +ostree_repo_init local +do_remote_add local collection-repo --collection-id org.example.CollectionRepo +do_remote_add local no-collection-repo + +do_pull local no-collection-repo goodncref1 +do_pull local no-collection-repo sortofbadncref1 +if do_pull local collection-repo badcref1 +then + assert_not_reached "pulling a commit without collection ID from a repo with collection ID should fail" +fi +if do_pull local collection-repo badcref2 +then + assert_not_reached "pulling a commit with a mismatched collection ID from a repo with collection ID should fail" +fi +if do_pull local collection-repo badcref3 +then + assert_not_reached "pulling a commit with empty collection ID from repo with collection ID should fail" +fi +do_pull local collection-repo goodcref1 +if do_pull local collection-repo badcref4 +then + assert_not_reached "pulling a commit that was not requested from repo with collection ID should fail" +fi + +echo "ok 5 pull refs from remote repos" + +do_local_pull local no-collection-local-repo goodnclref1 +do_local_pull local no-collection-local-repo sortofbadnclref1 +if do_local_pull local collection-local-repo badclref1 +then + assert_not_reached "pulling a commit without collection ID from a repo with collection ID should fail" +fi +if do_local_pull local collection-local-repo badclref2 +then + assert_not_reached "pulling a commit with a mismatched collection ID from a repo with collection ID should fail" +fi +if do_local_pull local collection-local-repo badclref3 +then + assert_not_reached "pulling a commit with empty collection ID from repo with collection ID should fail" +fi +do_local_pull local collection-local-repo goodclref1 +if do_local_pull local collection-local-repo badclref4 +then + assert_not_reached "pulling a commit that was not requested from repo with collection ID should fail" +fi + +echo "ok 6 pull refs from local repos" + +ostree_repo_init local-mirror +do_remote_add local-mirror collection-repo --collection-id org.example.CollectionRepo +# Generate a summary in the local mirror; don't use do_summary to avoid gpg +${CMD_PREFIX} ostree --repo=local-mirror summary --update +summarysig=$(sha256sum < local-mirror/summary | cut -f 1 -d ' ') +# Mirror subset of refs: A collection-ref version of https://github.com/ostreedev/ostree/issues/846 +${CMD_PREFIX} ostree --repo=local-mirror find-remotes --pull --mirror --finders=config org.example.CollectionRepo goodcref1 +newsummarysig=$(sha256sum < local-mirror/summary | cut -f 1 -d ' ') +assert_streq ${summarysig} ${newsummarysig} + +echo "ok 7 mirror pull subset of collection-refs with summary" diff --git a/tests/test-pull-commit-only.sh b/tests/test-pull-commit-only.sh new file mode 100755 index 0000000..caca92f --- /dev/null +++ b/tests/test-pull-commit-only.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# +# Copyright (C) 2015 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +echo '1..1' + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +${CMD_PREFIX} ostree --repo=repo pull --commit-metadata-only origin main +find repo/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^1$" +${CMD_PREFIX} ostree --repo=repo fsck + +find repo/objects -name '*.file.*' | wc -l > commitcount +assert_file_has_content commitcount "^0$" + +find repo/objects -name '*.dirtree' | wc -l > commitcount +assert_file_has_content commitcount "^0$" + +echo "ok pull commit metadata only" diff --git a/tests/test-pull-contenturl.sh b/tests/test-pull-contenturl.sh new file mode 100755 index 0000000..4dee0cc --- /dev/null +++ b/tests/test-pull-contenturl.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# +# Copyright (C) 2016 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..2" + +COMMIT_SIGN="" +if has_gpgme; then + COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" +fi + +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" + +# create a summary +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo \ + summary -u ${COMMIT_SIGN} + +# Let's bring up an identical server in which meta files are missing +cd ${test_tmpdir} +mkdir httpd-content +cd httpd-content +cp -a ${test_tmpdir}/ostree-srv ostree + +# delete all the meta stuff from here +rm ostree/gnomerepo/summary +if has_gpgme; then + rm ostree/gnomerepo/summary.sig + find ostree/gnomerepo/objects -name '*.commitmeta' | xargs rm +fi + +# delete all the content stuff from there +find ${test_tmpdir}/ostree-srv/gnomerepo/objects \ + ! -name '*.commitmeta' -type f | xargs rm + +${OSTREE_HTTPD} --autoexit --daemonize -p ${test_tmpdir}/httpd-content-port +content_port=$(cat ${test_tmpdir}/httpd-content-port) +echo "http://127.0.0.1:${content_port}" > ${test_tmpdir}/httpd-content-address + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +if has_gpgme; then VERIFY=true; else VERIFY=false; fi +${CMD_PREFIX} ostree --repo=repo remote add origin \ + --set=gpg-verify=$VERIFY --set=gpg-verify-summary=$VERIFY \ + --contenturl=$(cat httpd-content-address)/ostree/gnomerepo \ + $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo pull origin:main + +echo "ok pull objects from contenturl" + +if ! has_gpgme; then + echo "ok don't pull sigs from contenturl # SKIP not compiled with gpgme" +else + echo "ok don't pull sigs from contenturl" +fi diff --git a/tests/test-pull-corruption.sh b/tests/test-pull-corruption.sh new file mode 100755 index 0000000..61da575 --- /dev/null +++ b/tests/test-pull-corruption.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# +# Copyright (C) 2011,2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +# If gjs is not installed, skip the test +if ! gjs --help >/dev/null 2>&1; then + echo "1..0 # SKIP no gjs" + exit 0 +fi + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +echo '1..3' + +repopath=${test_tmpdir}/ostree-srv/gnomerepo +cp -a ${repopath} ${repopath}.orig + +do_corrupt_pull_test() { + cd ${test_tmpdir} + rm repo -rf + mkdir repo + ostree_repo_init repo + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + if ${CMD_PREFIX} ostree --repo=repo pull origin main; then + assert_not_reached "pull unexpectedly succeeded!" + fi + rm -rf ${repopath} + cp -a ${repopath}.orig ${repopath} + ${CMD_PREFIX} ostree --repo=repo pull origin main + if ${CMD_PREFIX} ostree --repo=repo fsck; then + echo "ok pull with correct data worked" + else + assert_not_reached "pull with correct data failed!" + fi +} + +# FIXME - ignore errors here since gjs in RHEL7 has the final +# unrooting bug +gjs $(dirname $0)/corrupt-repo-ref.js ${repopath} main || true +assert_file_has_content corrupted-status.txt 'Changed byte' +do_corrupt_pull_test +echo "ok corruption" + +if ! skip_one_without_user_xattrs; then + # Set up a corrupted commit object + rm ostree-srv httpd repo -rf + setup_fake_remote_repo1 "archive" + rev=$(ostree --repo=ostree-srv/gnomerepo rev-parse main) + corruptrev=$(echo ${rev} hello | sha256sum | cut -f 1 -d ' ') + assert_not_streq ${rev} ${corruptrev} + rev_path=ostree-srv/gnomerepo/objects/${rev:0:2}/${rev:2}.commit + corruptrev_path=ostree-srv/gnomerepo/objects/${corruptrev:0:2}/${corruptrev:2}.commit + mkdir -p $(dirname ${corruptrev_path}) + mv ${rev_path} ${corruptrev_path} + echo ${corruptrev} > ostree-srv/gnomerepo/refs/heads/main + ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + if ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo fsck 2>err.txt; then + assert_not_reached "fsck with corrupted commit worked?" + fi + assert_file_has_content_literal err.txt "Corrupted commit object; checksum expected='${corruptrev}' actual='${rev}'" + + # Do a pull-local; this should succeed since we don't verify checksums + # for local repos by default. + rm repo err.txt -rf + ostree_repo_init repo --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo pull-local ostree-srv/gnomerepo main + + rm repo err.txt -rf + ostree_repo_init repo --mode=bare-user + if ${CMD_PREFIX} ostree --repo=repo pull-local --untrusted ostree-srv/gnomerepo main 2>err.txt; then + assert_not_reached "pull-local --untrusted worked?" + fi + assert_file_has_content_literal err.txt "Corrupted commit object; checksum expected='${corruptrev}' actual='${rev}'" + + rm repo err.txt -rf + ostree_repo_init repo --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>err.txt; then + assert_not_reached "pull unexpectedly succeeded!" + fi + assert_file_has_content_literal err.txt "Corrupted commit object; checksum expected='${corruptrev}' actual='${rev}'" + echo "ok pull commit corruption" +fi diff --git a/tests/test-pull-depth.sh b/tests/test-pull-depth.sh new file mode 100755 index 0000000..1206c6c --- /dev/null +++ b/tests/test-pull-depth.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +echo '1..1' + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +${CMD_PREFIX} ostree --repo=repo pull --depth=0 origin main +find repo/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^1$" + +${CMD_PREFIX} ostree --repo=repo pull --depth=0 origin main +find repo/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^1$" + +${CMD_PREFIX} ostree --repo=repo pull --depth=1 origin main +find repo/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^2$" + +${CMD_PREFIX} ostree --repo=repo pull --depth=1 origin main +find repo/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^2$" + +${CMD_PREFIX} ostree --repo=repo pull --depth=-1 origin main +find repo/objects -name '*.commit' | wc -l > commitcount +assert_file_has_content commitcount "^3$" + +echo "ok pull depth" diff --git a/tests/test-pull-large-metadata.sh b/tests/test-pull-large-metadata.sh new file mode 100755 index 0000000..acf42c7 --- /dev/null +++ b/tests/test-pull-large-metadata.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +echo '1..1' + +# Overwrite the commit object with 20 M of +cd ${test_tmpdir} +rev=$(cd ostree-srv && ${CMD_PREFIX} ostree --repo=gnomerepo rev-parse main) +dd if=/dev/zero bs=1M count=20 of=ostree-srv/gnomerepo/objects/$(echo $rev | cut -b 1-2)/$(echo $rev | cut -b 3-).commit + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>pulllog.txt 1>&2; then + assert_not_reached "pull unexpectedly succeeded!" +fi +assert_file_has_content pulllog.txt "exceeded maximum" + +echo "ok" diff --git a/tests/test-pull-localcache.sh b/tests/test-pull-localcache.sh new file mode 100755 index 0000000..3de1e5a --- /dev/null +++ b/tests/test-pull-localcache.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# +# Copyright (C) 2017 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +echo '1..2' + +cd ${test_tmpdir} +gnomerepo_url="$(cat httpd-address)/ostree/gnomerepo" + +# Set up our local cache +ostree_repo_init repo-local --mode "archive" +${CMD_PREFIX} ostree --repo=repo-local remote add --set=gpg-verify=false origin ${gnomerepo_url} + +init_repo() { + ostree_repo_init repo --mode "archive" + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin ${gnomerepo_url} +} + +# Pull the contents to our local cache +${CMD_PREFIX} ostree --repo=repo-local pull origin main +rm files -rf +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo checkout main files +echo anewfile > files/anewfile +commit=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit -b main --tree=dir=files) + +# Check that pulling a new commit of the same tree hits our cache +rm -rf repo +init_repo +${CMD_PREFIX} ostree --repo=repo pull --localcache-repo repo-local origin main >out.txt +assert_file_has_content out.txt '3 metadata, 1 content objects fetched (4 meta, 5 content local)' +echo "ok pull --localcache-repo" + +# Check that pulling the same commit works as well +rm -rf repo +init_repo +${CMD_PREFIX} ostree --repo=repo-local pull origin $commit +${CMD_PREFIX} ostree --repo=repo pull -L repo-local origin main +commit2=$(${CMD_PREFIX} ostree --repo=repo rev-parse main) +[[ $commit == $commit2 ]] +# and check that it's not partial +rm -rf files +${CMD_PREFIX} ostree --repo=repo checkout main files +test -f files/anewfile +echo "ok pull --localcache-repo same commit" diff --git a/tests/test-pull-metalink.sh b/tests/test-pull-metalink.sh new file mode 100755 index 0000000..263d29b --- /dev/null +++ b/tests/test-pull-metalink.sh @@ -0,0 +1,167 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +echo '1..9' + +# And another web server acting as the metalink server +cd ${test_tmpdir} +mkdir metalink-data +cd metalink-data +${OSTREE_HTTPD} --autoexit --daemonize -p ${test_tmpdir}/metalink-httpd-port +metalink_port=$(cat ${test_tmpdir}/metalink-httpd-port) +echo "http://127.0.0.1:${metalink_port}" > ${test_tmpdir}/metalink-httpd-address + +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u + +summary_path=${test_tmpdir}/ostree-srv/gnomerepo/summary + +echo -n broken > ${summary_path}.bad + +cd ${test_tmpdir} + +cat > metalink-valid-summary.xml < + $(stat -c '%s' ${summary_path}) + + $(md5sum ${summary_path} | cut -f 1 -d ' ') + $(sha256sum ${summary_path} | cut -f 1 -d ' ') + $(sha512sum ${summary_path} | cut -f 1 -d ' ') + + + $(cat httpd-address)/ostree/gnomerepo/summary.bad + $(cat httpd-address)/ostree/gnomerepo/nosuchfile + $(cat httpd-address)/ostree/gnomerepo/summary + + +EOF + +cat > ${test_tmpdir}/metalink-data/metalink.xml < + + + $(cat metalink-valid-summary.xml) + + +EOF + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin metalink=$(cat metalink-httpd-address)/metalink.xml +${CMD_PREFIX} ostree --repo=repo pull origin:main +${CMD_PREFIX} ostree --repo=repo rev-parse origin:main +${CMD_PREFIX} ostree --repo=repo fsck +echo "ok pull via metalink" + +# Test fetching the summary through ostree_repo_remote_fetch_summary() +${CMD_PREFIX} ostree --repo=repo remote refs origin > origin_refs +assert_file_has_content origin_refs "main" +echo "ok remote refs via metalink" + +cp metalink-data/metalink.xml{,.orig} +cp ostree-srv/gnomerepo/summary{,.orig} + +test_metalink_pull_error() { + msg=$1 + rm repo -rf + mkdir repo + ostree_repo_init repo + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin metalink=$(cat metalink-httpd-address)/metalink.xml + if ${CMD_PREFIX} ostree --repo=repo pull origin:main 2>err.txt; then + assert_not_reached "pull unexpectedly succeeded" + fi + assert_file_has_content err.txt "${msg}" +} + +cd ${test_tmpdir} +sed -e 's,.*,bacon,' < metalink-data/metalink.xml.orig > metalink-data/metalink.xml +test_metalink_pull_error "Invalid hash digest for sha512" +echo "ok metalink err hash format" + +cd ${test_tmpdir} +sed -e 's,.*,'$( (echo -n dummy; cat ${summary_path}) | sha512sum | cut -f 1 -d ' ')',' < metalink-data/metalink.xml.orig > metalink-data/metalink.xml +test_metalink_pull_error "Expected checksum is .* but actual is" +echo "ok metalink err hash sha512" + +cd ${test_tmpdir} +cp metalink-data/metalink.xml.orig metalink-data/metalink.xml +echo -n moo > ostree-srv/gnomerepo/summary +test_metalink_pull_error "Expected size is .* bytes but content is 3 bytes" +echo "ok metalink err size" +cp ostree-srv/gnomerepo/summary{.orig,} + +cd ${test_tmpdir} +grep -v sha256 < metalink-data/metalink.xml.orig |grep -v sha512 > metalink-data/metalink.xml +test_metalink_pull_error "No.*verification.*with known.*hash" +echo "ok metalink err no verify" + +cd ${test_tmpdir} +grep -v ' metalink-data/metalink.xml +test_metalink_pull_error "No.*url.*method.*elements" +echo "ok metalink err no url" + +cd ${test_tmpdir} +echo bacon > metalink-data/metalink.xml +test_metalink_pull_error "Document must begin with an element" +echo "ok metalink err malformed" + +cat > ${test_tmpdir}/metalink-data/metalink.xml < + + + + + + hello world + + + + + + $(cat metalink-valid-summary.xml) + + + + + + hello world + + + + + +EOF + +cd ${test_tmpdir} +rm repo -rf +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin metalink=$(cat metalink-httpd-address)/metalink.xml +${CMD_PREFIX} ostree --repo=repo pull origin:main +${CMD_PREFIX} ostree --repo=repo rev-parse origin:main +${CMD_PREFIX} ostree --repo=repo fsck +echo "ok pull via metalink with nested data" diff --git a/tests/test-pull-mirror-summary.sh b/tests/test-pull-mirror-summary.sh new file mode 100755 index 0000000..a2a98ba --- /dev/null +++ b/tests/test-pull-mirror-summary.sh @@ -0,0 +1,128 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +COMMIT_SIGN="" +if has_gpgme; then + COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" + echo "1..5" +else + # Only one test don't need GPG support + echo "1..1" +fi + +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" + +# Now, setup multiple branches +mkdir ${test_tmpdir}/ostree-srv/other-files +cd ${test_tmpdir}/ostree-srv/other-files +echo 'hello world another object' > hello-world +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b other -s "A commit" -m "Another Commit body" + +mkdir ${test_tmpdir}/ostree-srv/yet-other-files +cd ${test_tmpdir}/ostree-srv/yet-other-files +echo 'hello world yet another object' > yet-another-hello-world +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b yet-another -s "A commit" -m "Another Commit body" + +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u + +prev_dir=`pwd` +cd ${test_tmpdir} +ostree_repo_init repo --mode=archive +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo pull --mirror origin +assert_has_file repo/summary +${CMD_PREFIX} ostree --repo=repo checkout -U main main-copy +assert_file_has_content main-copy/baz/cow "moo" +${CMD_PREFIX} ostree --repo=repo checkout -U other other-copy +assert_file_has_content other-copy/hello-world "hello world another object" +${CMD_PREFIX} ostree --repo=repo checkout -U yet-another yet-another-copy +assert_file_has_content yet-another-copy/yet-another-hello-world "hello world yet another object" +${CMD_PREFIX} ostree --repo=repo fsck +rev=$(ostree --repo=repo rev-parse main) +find repo/objects -name '*.filez' | while read name; do + mode=$(stat -c '%a' "${name}") + if test "${mode}" = 600; then + assert_not_reached "Content object unreadable by others: ${mode}" + fi +done +echo "ok pull mirror summary" + +if ! has_gpgme; then + exit 0; +fi + +cd $prev_dir + +cd ${test_tmpdir} +rm -rf repo +ostree_repo_init repo --mode=archive +${OSTREE} --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo +echo "ok pull mirror without checking signed summary" + +cd ${test_tmpdir} +rm -rf repo +ostree_repo_init repo --mode=archive +${OSTREE} --repo=repo remote add --set=gpg-verify-summary=true origin $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} --repo=repo pull --mirror origin 2>err.txt; then + assert_not_reached "Mirroring unexpectedly succeeded" +fi +echo "ok pull mirror without signed summary" + +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} + +cd ${test_tmpdir} +rm -rf repo +ostree_repo_init repo --mode=archive +${OSTREE} --repo=repo remote add --set=gpg-verify-summary=true origin $(cat httpd-address)/ostree/gnomerepo +${OSTREE} --repo=repo pull --mirror origin +assert_has_file repo/summary +assert_has_file repo/summary.sig +echo "ok pull mirror with signed summary" + +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.good} +truncate --size=1 ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig + +cd ${test_tmpdir} +rm -rf repo +mkdir repo +ostree_repo_init repo --mode=archive +${OSTREE} --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo +${OSTREE} --repo=repo pull --mirror origin +assert_has_file repo/summary +assert_has_file repo/summary.sig +mv ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.good,} +echo "ok pull mirror with invalid summary sig and no verification" + +# Uncomment when we support mirroring deltas +# +# ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo static-delta generate main +# origmain=$(ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo rev-parse main^) +# newmain=$(ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo rev-parse main) +# ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} +# ${OSTREE} --repo=repo pull --mirror origin +# ${OSTREE} --repo=repo static-delta list >deltas.txt +# assert_file_has_content deltas.txt "${origmain}-${newmain}" + +# echo "ok pull mirror with signed summary covering static deltas" diff --git a/tests/test-pull-mirrorlist.sh b/tests/test-pull-mirrorlist.sh new file mode 100755 index 0000000..ed65eb6 --- /dev/null +++ b/tests/test-pull-mirrorlist.sh @@ -0,0 +1,108 @@ +#!/bin/bash +# +# Copyright (C) 2016 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..3" + +setup_fake_remote_repo1 "archive" + +setup_mirror () { + name=$1; shift + + cd ${test_tmpdir} + mkdir $name + cd $name + cp -a ${test_tmpdir}/ostree-srv ostree + + ${OSTREE_HTTPD} --autoexit --daemonize \ + -p ${test_tmpdir}/${name}-port + port=$(cat ${test_tmpdir}/${name}-port) + echo "http://127.0.0.1:${port}" > ${test_tmpdir}/${name}-address +} + +setup_mirror content_mirror1 +setup_mirror content_mirror2 +setup_mirror content_mirror3 + +# Let's delete a file from 1 so that it falls back on 2 +cd ${test_tmpdir}/content_mirror1/ostree/gnomerepo +filez=$((find objects/ -name '*.filez' || true) | head -n 1) +rm ${filez} + +# Let's delete a file from 1 and 2 so that it falls back on 3 +cd ${test_tmpdir}/content_mirror1/ostree/gnomerepo +filez=$((find objects/ -name '*.filez' || true) | head -n 1) +rm ${filez} +cd ${test_tmpdir}/content_mirror2/ostree/gnomerepo +rm ${filez} + +# OK, let's just shove the mirrorlist in the first httpd +cat > ${test_tmpdir}/ostree-srv/mirrorlist <${test_tmpdir}/original_commits + + +gnomerepo_url="$(cat httpd-address)/ostree/gnomerepo" +mkdir mirror-srv +cd mirror-srv +mkdir gnomerepo +ostree_repo_init gnomerepo --mode "archive" +${CMD_PREFIX} ostree --repo=gnomerepo remote add --set=gpg-verify=false origin ${gnomerepo_url} +${CMD_PREFIX} ostree --repo=gnomerepo pull --mirror --depth=-1 origin main + +find gnomerepo/objects -name '*.commit' | cut -d/ -f3- | sort >${test_tmpdir}/mirror_commits + +if ! cmp --quiet ${test_tmpdir}/original_commits ${test_tmpdir}/mirror_commits +then + assert_not_reached 'original repository and its mirror should have the same commits' +fi + +cd ${test_tmpdir} +mkdir mirror-httpd +cd mirror-httpd +ln -s ${test_tmpdir}/mirror-srv ostree +mirror_log="${test_tmpdir}/mirror_log" +${OSTREE_HTTPD} --log-file=${mirror_log} --autoexit --daemonize -p ${test_tmpdir}/mirror-httpd-port +port=$(cat ${test_tmpdir}/mirror-httpd-port) +echo "http://127.0.0.1:${port}" > ${test_tmpdir}/mirror-httpd-address + +cd ${test_tmpdir} +mirrorrepo_url="$(cat mirror-httpd-address)/ostree/gnomerepo" +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin ${gnomerepo_url} +rm -rf ${test_tmpdir}/ostree-srv/gnomerepo +if ${CMD_PREFIX} ostree --repo=repo pull --depth=-1 origin main +then + assert_not_reached 'pulling from removed remote should have failed' +fi + +if ! ${CMD_PREFIX} ostree --repo=repo pull --depth=-1 --url=${mirrorrepo_url} origin main +then + cat ${mirror_log} + assert_not_reached 'fetching from the overridden URL should succeed' +fi +find repo/objects -name '*.commit' | cut -d/ -f3- | sort >${test_tmpdir}/repo_commits + +if ! cmp --quiet ${test_tmpdir}/original_commits ${test_tmpdir}/repo_commits +then + assert_not_reached 'original repository and its mirror should have the same commits' +fi + +echo "ok pull url override" diff --git a/tests/test-pull-repeated.sh b/tests/test-pull-repeated.sh new file mode 100755 index 0000000..f0ea157 --- /dev/null +++ b/tests/test-pull-repeated.sh @@ -0,0 +1,103 @@ +#!/bin/bash +# +# Copyright (C) 2016 Red Hat +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +COMMIT_SIGN="" +if has_gpgme; then + COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" +fi + +echo "1..4" + +# Test pulling from a repo which gives error 500 (internal server error) a lot of the time. +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" --random-500s=50 + +pushd ${test_tmpdir} +ostree_repo_init repo --mode=archive +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +for x in $(seq 200); do + if ${CMD_PREFIX} ostree --repo=repo pull --mirror origin main 2>err.txt; then + echo "Success on iteration ${x}" + break; + fi + assert_file_has_content err.txt "\(500.*Internal Server Error\)\|\(HTTP 500\)" +done + +${CMD_PREFIX} ostree --repo=repo fsck +${CMD_PREFIX} ostree --repo=repo rev-parse main + +popd +echo "ok repeated pull after 500s" + +# Sanity check with no network retries and 408s given, pull should fail. +rm ostree-srv httpd repo -rf +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" --random-408s=99 + +pushd ${test_tmpdir} +ostree_repo_init repo --mode=archive +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +assert_fail ${CMD_PREFIX} ostree --repo=repo pull --mirror origin --network-retries=0 main 2>err.txt +assert_file_has_content err.txt "\(408.*Request Timeout\)\|\(HTTP 408\)" + +popd +echo "ok no retries after a 408" + +# Test pulling a repo which gives error 408 (request timeout) a lot of the time. +rm ostree-srv httpd repo -rf +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" --random-408s=50 + +pushd ${test_tmpdir} +ostree_repo_init repo --mode=archive +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +for x in $(seq 40); do + if ${CMD_PREFIX} ostree --repo=repo pull --mirror origin --network-retries=2 main 2>err.txt; then + echo "Success on iteration ${x}" + break; + fi + assert_file_has_content err.txt "\(408.*Request Timeout\)\|\(HTTP 408\)" +done + +${CMD_PREFIX} ostree --repo=repo fsck +${CMD_PREFIX} ostree --repo=repo rev-parse main + +popd +echo "ok repeated pull after 408s" + +# Test pulling a repo that gives 408s a lot of the time, with many network retries. +rm ostree-srv httpd repo -rf +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" --random-408s=50 + +pushd ${test_tmpdir} +ostree_repo_init repo --mode=archive +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +# We limit 408s above to 100, so 100 retries should be enough always. +${CMD_PREFIX} ostree --repo=repo pull --mirror origin --network-retries=100 main +echo "Success with big number of network retries" + +${CMD_PREFIX} ostree --repo=repo fsck +${CMD_PREFIX} ostree --repo=repo rev-parse main + +popd +echo "ok big number of retries with one 408" diff --git a/tests/test-pull-resume.sh b/tests/test-pull-resume.sh new file mode 100755 index 0000000..8fa4a29 --- /dev/null +++ b/tests/test-pull-resume.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# +# Copyright (C) 2013 Jeremy Whiting +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" "" "--force-range-requests" + +echo '1..1' + +repopath=${test_tmpdir}/ostree-srv/gnomerepo +cp -a ${repopath} ${repopath}.orig + +cd ${test_tmpdir} +rm repo -rf +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +maxtries=`find ${repopath}/objects | wc -l` +maxtries=`expr $maxtries \* 2` + +for ((i = 0; i < $maxtries; i=i+1)) +do + if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>err.log; then + break + fi + assert_file_has_content err.log 'error:.*\(Download incomplete\)\|\(Transferred a partial file\)' +done +if ${CMD_PREFIX} ostree --repo=repo fsck; then + echo "ok, pull succeeded!" +else + assert_not_reached "pull failed!" +fi +rm -rf ${repopath} +cp -a ${repopath}.orig ${repopath} diff --git a/tests/test-pull-sizes.sh b/tests/test-pull-sizes.sh new file mode 100755 index 0000000..1ce0a73 --- /dev/null +++ b/tests/test-pull-sizes.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Copyright (C) 2019 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Committing SELinux attributes throws off the hardcoded sizes below +export OSTREE_NO_XATTRS=1 +setup_fake_remote_repo1 "archive" "--generate-sizes" + +echo '1..3' + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +# Pull commit metadata only. All size and objects will be needed. +${CMD_PREFIX} ostree --repo=repo pull --commit-metadata-only origin main +${CMD_PREFIX} ostree --repo=repo show --print-sizes origin:main > show.txt +assert_file_has_content show.txt 'Compressed size (needed/total): 637[  ]bytes/637[  ]bytes' +assert_file_has_content show.txt 'Unpacked size (needed/total): 457[  ]bytes/457[  ]bytes' +assert_file_has_content show.txt 'Number of objects (needed/total): 10/10' +echo "ok sizes commit metadata only" + +# Pull the parent commit so we get most of the objects +parent=$(${CMD_PREFIX} ostree --repo=repo rev-parse origin:main^) +${CMD_PREFIX} ostree --repo=repo pull origin ${parent} +${CMD_PREFIX} ostree --repo=repo show --print-sizes origin:main > show.txt +assert_file_has_content show.txt 'Compressed size (needed/total): 501[  ]bytes/637[  ]bytes' +assert_file_has_content show.txt 'Unpacked size (needed/total): 429[  ]bytes/457[  ]bytes' +assert_file_has_content show.txt 'Number of objects (needed/total): 6/10' +echo "ok sizes commit partial" + +# Finish pulling the commit and check that no objects needed +${CMD_PREFIX} ostree --repo=repo pull origin main +${CMD_PREFIX} ostree --repo=repo show --print-sizes origin:main > show.txt +assert_file_has_content show.txt 'Compressed size (needed/total): 0[  ]bytes/637[  ]bytes' +assert_file_has_content show.txt 'Unpacked size (needed/total): 0[  ]bytes/457[  ]bytes' +assert_file_has_content show.txt 'Number of objects (needed/total): 0/10' +echo "ok sizes commit full" diff --git a/tests/test-pull-subpath.sh b/tests/test-pull-subpath.sh new file mode 100755 index 0000000..3bf89af --- /dev/null +++ b/tests/test-pull-subpath.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +echo '1..4' + +repopath=${test_tmpdir}/ostree-srv/gnomerepo +cp -a ${repopath} ${repopath}.orig + +for remoteurl in $(cat httpd-address)/ostree/gnomerepo \ + file://$(pwd)/ostree-srv/gnomerepo; do +cd ${test_tmpdir} +rm repo -rf +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin ${remoteurl} + +${CMD_PREFIX} ostree --repo=repo pull --subpath=/baz/deeper --subpath=/baz/another origin main + +${CMD_PREFIX} ostree --repo=repo ls origin:main /baz/deeper +${CMD_PREFIX} ostree --repo=repo ls origin:main /baz/another +if ${CMD_PREFIX} ostree --repo=repo ls origin:main /firstfile 2>err.txt; then + assert_not_reached +fi +assert_file_has_content err.txt "Couldn't find file object" +rev=$(${CMD_PREFIX} ostree --repo=repo rev-parse origin:main) +assert_has_file repo/state/${rev}.commitpartial + +# Test pulling a file, not a dir +${CMD_PREFIX} ostree --repo=repo pull --subpath=/firstfile origin main +${CMD_PREFIX} ostree --repo=repo ls origin:main /firstfile + +${CMD_PREFIX} ostree --repo=repo pull origin main +assert_not_has_file repo/state/${rev}.commitpartial +${CMD_PREFIX} ostree --repo=repo fsck +echo "ok subpaths" + +rm -rf repo + +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin ${remoteurl} + +# Pull a directory which is not the first in the commit (/baz/another is before) +${CMD_PREFIX} ostree --repo=repo pull --subpath=/baz/deeper origin main + +# Ensure it is there +${CMD_PREFIX} ostree --repo=repo ls origin:main /baz/deeper + +# Now prune, this should not prune the /baz/deeper dirmeta even if the +# /baz/another dirmeta is not in the repo. +${CMD_PREFIX} ostree --repo=repo prune --refs-only + +# Ensure it is still there +${CMD_PREFIX} ostree --repo=repo ls origin:main /baz/deeper + +echo "ok prune with commitpartial" + +done diff --git a/tests/test-pull-summary-sigs.sh b/tests/test-pull-summary-sigs.sh new file mode 100755 index 0000000..401e88c --- /dev/null +++ b/tests/test-pull-summary-sigs.sh @@ -0,0 +1,282 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +COMMIT_SIGN="" +if has_gpgme; then + COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" + echo "1..10" +else + # Only one test don't need GPG support + echo "1..1" +fi + +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" + +# Now, setup multiple branches +mkdir ${test_tmpdir}/ostree-srv/other-files +cd ${test_tmpdir}/ostree-srv/other-files +echo 'hello world another object' > hello-world +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b other -s "A commit" -m "Another Commit body" + +mkdir ${test_tmpdir}/ostree-srv/yet-other-files +cd ${test_tmpdir}/ostree-srv/yet-other-files +echo 'hello world yet another object' > yet-another-hello-world +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b yet-another -s "A commit" -m "Another Commit body" + +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u + +prev_dir=`pwd` +cd ${test_tmpdir} +ostree_repo_init repo --mode=archive +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo pull --mirror origin +assert_has_file repo/summary +${CMD_PREFIX} ostree --repo=repo checkout -U main main-copy +assert_file_has_content main-copy/baz/cow "moo" +${CMD_PREFIX} ostree --repo=repo checkout -U other other-copy +assert_file_has_content other-copy/hello-world "hello world another object" +${CMD_PREFIX} ostree --repo=repo checkout -U yet-another yet-another-copy +assert_file_has_content yet-another-copy/yet-another-hello-world "hello world yet another object" +${CMD_PREFIX} ostree --repo=repo fsck +echo "ok pull mirror summary" + +if ! has_gpgme; then + exit 0; +fi + +cd $prev_dir + +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} + +repo_reinit () { + cd ${test_tmpdir} + rm -rf repo + mkdir repo + ostree_repo_init repo --mode=archive + ${OSTREE} --repo=repo remote add --set=gpg-verify-summary=true origin $(cat httpd-address)/ostree/gnomerepo +} + +cd ${test_tmpdir} +repo_reinit +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig + +rm repo/tmp/cache/summaries/origin +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin + +echo "ok pull with signed summary" + +touch repo/tmp/cache/summaries/foo +touch repo/tmp/cache/summaries/foo.sig +${OSTREE} --repo=repo prune +assert_not_has_file repo/tmp/cache/summaries/foo +assert_not_has_file repo/tmp/cache/summaries/foo.sig +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +echo "ok prune summary cache" + +cd ${test_tmpdir} +repo_reinit +mkdir cachedir +${OSTREE} --repo=repo pull --cache-dir=cachedir origin main +assert_not_has_file repo/tmp/cache/summaries/origin +assert_not_has_file repo/tmp/cache/summaries/origin.sig +assert_has_file cachedir/summaries/origin +assert_has_file cachedir/summaries/origin.sig + +rm cachedir/summaries/origin +${OSTREE} --repo=repo pull --cache-dir=cachedir origin main +assert_not_has_file repo/tmp/cache/summaries/origin +assert_has_file cachedir/summaries/origin + +echo "ok pull with signed summary and cachedir" + +cd ${test_tmpdir} +repo_reinit +mv ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.good} +echo invalid > ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig +if ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Successful pull with invalid GPG sig" +fi +assert_file_has_content err.txt "no signatures found" +mv ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.good,} +echo "ok pull with invalid summary gpg signature fails" + +cd ${test_tmpdir} +repo_reinit +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{,.good} +# Some leading garbage +(echo invalid && cat ${test_tmpdir}/ostree-srv/gnomerepo/summary) > summary.bad.tmp && mv summary.bad.tmp ${test_tmpdir}/ostree-srv/gnomerepo/summary +if ${OSTREE} --repo=repo pull origin main; then + assert_not_reached "Successful pull with invalid summary" +fi +mv ${test_tmpdir}/ostree-srv/gnomerepo/summary{.good,} +echo "ok pull with invalid summary (leading garbage) fails" + +# Generate a delta +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo static-delta generate --empty main +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} + +cd ${test_tmpdir} +repo_reinit +${OSTREE} --repo=repo pull origin main +echo "ok pull delta with signed summary" + +# Verify 'ostree remote summary' output. +${OSTREE} --repo=repo remote summary origin > summary.txt +assert_file_has_content summary.txt "* main" +assert_file_has_content summary.txt "* other" +assert_file_has_content summary.txt "* yet-another" +assert_file_has_content summary.txt "found 1 signature" +assert_file_has_content summary.txt "Good signature from \"Ostree Tester \"" +grep static-deltas summary.txt > static-deltas.txt +assert_file_has_content static-deltas.txt \ + $(${OSTREE} --repo=repo rev-parse origin:main) + +## Tests for handling of cached summaries while racing with remote summary updates + +# Make 2 different but valid summary/signature pairs to test races with +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{,.1} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.1} +mkdir ${test_tmpdir}/ostree-srv/even-another-files +cd ${test_tmpdir}/ostree-srv/even-another-files +echo 'hello world even another object' > even-another-hello-world +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b even-another -s "A commit" -m "Another Commit body" +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{,.2} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.2} +cd ${test_tmpdir} + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a pull race where the client gets the old summary and the new +# summary signature since it was generated on the server between the +# requests +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +if ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Successful pull with old summary" +fi +assert_file_has_content err.txt "BAD signature" +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish correct summary and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok pull with signed summary remote old summary" + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a pull race where the client gets the new summary and the old +# summary signature. This is unlikely to happen except if the web server +# is caching the old signature. This should succeed because the cached +# old summary is used. +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish correct signature and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok pull with signed summary remote old summary signature" + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a broken summary cache to see if it can be recovered from. +# Prior to commit c4c2b5eb the client would save the summary to the +# cache before validating the signature. That would mean the cache would +# have mismatched summary and signature and ostree would remain +# deadlocked there until the remote published a new signature. +# +# First pull with OSTREE_REPO_TEST_ERROR=invalid-cache to see the +# invalid cache is detected. Then pull again to check if it can be +# recovered from. +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 repo/tmp/cache/summaries/origin +if OSTREE_REPO_TEST_ERROR=invalid-cache ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Should have hit OSTREE_REPO_TEST_ERROR_INVALID_CACHE" +fi +assert_file_has_content err.txt "OSTREE_REPO_TEST_ERROR_INVALID_CACHE" +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish new signature and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok pull with signed summary broken cache" diff --git a/tests/test-pull-untrusted.sh b/tests/test-pull-untrusted.sh new file mode 100755 index 0000000..ec48eb3 --- /dev/null +++ b/tests/test-pull-untrusted.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# +# Copyright (C) 2014 Alexander Larsson +# Copyright (C) 2018 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..1' + +setup_test_repository "bare" + +cd ${test_tmpdir} +tar xf ${test_srcdir}/ostree-path-traverse.tar.gz +rm -rf repo2 +ostree_repo_init repo2 --mode=archive +if ${CMD_PREFIX} ostree --repo=repo2 pull-local --untrusted ostree-path-traverse/repo pathtraverse-test 2>err.txt; then + fatal "pull-local unexpectedly succeeded" +fi +assert_file_has_content_literal err.txt 'Invalid / in filename ../afile' +echo "ok untrusted pull-local path traversal" diff --git a/tests/test-pull2-bareuseronly.sh b/tests/test-pull2-bareuseronly.sh new file mode 100755 index 0000000..1861425 --- /dev/null +++ b/tests/test-pull2-bareuseronly.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# Copyright (C) 2017 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo2 "archive" "--canonical-permissions" + +repo_mode=bare-user-only +. ${test_srcdir}/pull-test2.sh diff --git a/tests/test-refs-collections.sh b/tests/test-refs-collections.sh new file mode 100755 index 0000000..d33f498 --- /dev/null +++ b/tests/test-refs-collections.sh @@ -0,0 +1,156 @@ +#!/bin/bash +# +# Copyright © 2016 Red Hat, Inc. +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..2' + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo --collection-id org.example.Collection + +mkdir -p tree/root +touch tree/root/a + +# Add a few commits +seq 5 | while read i; do + echo a >> tree/root/a + ${CMD_PREFIX} ostree --repo=repo commit --branch=test-$i -m test -s test tree +done + +# The collection IDs should only be listed if --collections is passed. +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount +assert_file_has_content refscount "^5$" + +${CMD_PREFIX} ostree --repo=repo refs > refs +assert_file_has_content refs "^test\-1$" +assert_file_has_content refs "^test\-5$" +assert_not_file_has_content refs "org\.example\.Collection" + +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_file_has_content refs "^(org\.example\.Collection, test-1)$" +assert_file_has_content refs "^(org\.example\.Collection, test-5)$" + +# Similarly, the collection IDs should only be listed when filtering if --collections is passed. +${CMD_PREFIX} ostree --repo=repo refs --list org.example.Collection | wc -l > refscount +assert_file_has_content refscount "^0$" + +${CMD_PREFIX} ostree --repo=repo refs --collections --list org.example.Collection | wc -l > refscount +assert_file_has_content refscount "^5$" + +# --delete by itself should fail. +${CMD_PREFIX} ostree --repo=repo refs --delete 2>/dev/null || true +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.delete1 +assert_file_has_content refscount.delete1 "^5$" + +# Deleting specific refs should work. +${CMD_PREFIX} ostree refs --delete 2>/dev/null && (echo 1>&2 "refs --delete (without prefix) unexpectedly succeeded!"; exit 1) +${CMD_PREFIX} ostree --repo=repo refs --delete test-1 test-2 +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.delete2 +assert_file_has_content refscount.delete2 "^3$" +${CMD_PREFIX} ostree --repo=repo refs > refs.delete2 +assert_not_file_has_content refs.delete2 '^test-1$' +assert_not_file_has_content refs.delete2 '^test-2$' +assert_file_has_content refs.delete2 '^test-3$' + +# Deleting by collection ID should only work if --collections is passed. +${CMD_PREFIX} ostree refs --repo=repo --delete org.example.Collection +${CMD_PREFIX} ostree refs --repo=repo | wc -l > refscount.delete3 +assert_file_has_content refscount.delete3 "^3$" + +${CMD_PREFIX} ostree refs --repo=repo --collections --delete org.example.Collection +${CMD_PREFIX} ostree refs --repo=repo | wc -l > refscount.delete4 +assert_file_has_content refscount.delete4 "^0$" + +# Add a few more commits, to test --create +${CMD_PREFIX} ostree --repo=repo commit --branch=ctest -m ctest -s ctest tree + +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount +assert_file_has_content refscount "^1$" + +# and test mirrored branches +${CMD_PREFIX} ostree --repo=repo refs --collections --create=org.example.NewCollection:ctest-mirror ctest + +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount +assert_file_has_content refscount "^1$" +${CMD_PREFIX} ostree --repo=repo refs --collections | wc -l > refscount +assert_file_has_content refscount "^2$" + +${CMD_PREFIX} ostree --repo=repo refs > refs +assert_file_has_content refs "^ctest$" +assert_not_file_has_content refs "^ctest-mirror$" + +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_file_has_content refs "^(org\.example\.Collection, ctest)$" +assert_file_has_content refs "^(org\.example\.NewCollection, ctest-mirror)$" + +# Remote refs should be listed if they have collection IDs + +cd ${test_tmpdir} +mkdir collection-repo +ostree_repo_init collection-repo --collection-id org.example.RemoteCollection +mkdir -p adir +${CMD_PREFIX} ostree --repo=collection-repo commit --branch=rcommit -m rcommit -s rcommit adir +${CMD_PREFIX} ostree --repo=repo remote add --no-sign-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" +${CMD_PREFIX} ostree --repo=repo pull collection-repo-remote rcommit + +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_file_has_content refs "^(org\.example\.RemoteCollection, rcommit)$" + +${CMD_PREFIX} ostree --repo=repo refs --collections org.example.RemoteCollection > refs +assert_file_has_content refs "^(org\.example\.RemoteCollection, rcommit)$" + +${CMD_PREFIX} ostree --repo=repo refs --collections org.example.NonexistentID > refs +assert_not_file_has_content refs "^(org\.example\.RemoteCollection, rcommit)$" + +cd ${test_tmpdir} +mkdir no-collection-repo +ostree_repo_init no-collection-repo +mkdir -p adir2 +${CMD_PREFIX} ostree --repo=no-collection-repo commit --branch=rcommit2 -m rcommit2 -s rcommit2 adir2 +${CMD_PREFIX} ostree --repo=repo remote add --no-sign-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" +${CMD_PREFIX} ostree --repo=repo pull no-collection-repo-remote rcommit2 +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_not_file_has_content refs "rcommit2" + +echo "ok 1 refs collections" + +# Test that listing, creating and deleting refs works from an old repository +# where refs/mirrors doesn’t exist to begin with. +rm -rf repo/refs/mirrors +${CMD_PREFIX} ostree --repo=repo refs + +rm -rf repo/refs/mirrors +${CMD_PREFIX} ostree --repo=repo refs --collections + +rm -rf repo/refs/mirrors +${CMD_PREFIX} ostree --repo=repo refs --collections --create=org.example.NewCollection:ctest-mirror ctest +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_file_has_content refs "^(org\.example\.Collection, ctest)$" +assert_file_has_content refs "^(org\.example\.NewCollection, ctest-mirror)$" + +rm -rf repo/refs/mirrors +${CMD_PREFIX} ostree refs --repo=repo --collections --delete org.example.NonexistentCollection + +echo "ok 2 refs collections in old repository" diff --git a/tests/test-refs.sh b/tests/test-refs.sh new file mode 100755 index 0000000..d0f8e7d --- /dev/null +++ b/tests/test-refs.sh @@ -0,0 +1,220 @@ +#!/bin/bash +# +# Copyright (C) 2016 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" + +echo '1..7' + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo + +mkdir -p tree/root +touch tree/root/a + +# Add a few commits +seq 5 | while read i; do + echo a >> tree/root/a + ${CMD_PREFIX} ostree --repo=repo commit --branch=test-$i -m test -s test tree + ${CMD_PREFIX} ostree --repo=repo commit --branch=foo/test-$i -m test -s test tree +done + +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount +assert_file_has_content refscount "^10$" + +${CMD_PREFIX} ostree --repo=repo refs foo > refs +assert_not_file_has_content refs foo + +${CMD_PREFIX} ostree --repo=repo refs --list foo > refs +assert_file_has_content refs foo + +${CMD_PREFIX} ostree --repo=repo refs foo | wc -l > refscount.foo +assert_file_has_content refscount.foo "^5$" + +${CMD_PREFIX} ostree --repo=repo refs --delete 2>/dev/null || true +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.delete1 +assert_file_has_content refscount.delete1 "^10$" + +${CMD_PREFIX} ostree refs --delete 2>/dev/null && (echo 1>&2 "refs --delete (without prefix) unexpectedly succeeded!"; exit 1) +${CMD_PREFIX} ostree --repo=repo refs --delete test-1 test-2 +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.delete2 +assert_file_has_content refscount.delete2 "^8$" + +${CMD_PREFIX} ostree refs --repo=repo --delete foo +${CMD_PREFIX} ostree refs --repo=repo | wc -l > refscount.delete3 +assert_file_has_content refscount.delete3 "^3$" +assert_not_file_has_content reflist '^test-1$' + +#Add a few more commits, to test --create +${CMD_PREFIX} ostree --repo=repo commit --branch=ctest -m ctest -s ctest tree +${CMD_PREFIX} ostree --repo=repo commit --branch=foo/ctest -m ctest -s ctest tree + +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount +assert_file_has_content refscount "^5$" + +if ${CMD_PREFIX} ostree --repo=repo refs --create=ctest-new; then + assert_not_reached "refs --create unexpectedly succeeded without specifying an existing ref!" +fi +if ${CMD_PREFIX} ostree --repo=repo refs ctest --create; then + assert_not_reached "refs --create unexpectedly succeeded without specifying the ref to create!" +fi +if ${CMD_PREFIX} ostree --repo=repo refs does-not-exist --create=ctest-new; then + assert_not_reached "refs --create unexpectedly succeeded for a prefix that doesn't exist!" +fi +if ${CMD_PREFIX} ostree --repo=repo refs ctest --create=foo; then + assert_not_reached "refs --create unexpectedly succeeded for a prefix that is already in use by a folder!" +fi +if ${CMD_PREFIX} ostree --repo=repo refs foo/ctest --create=ctest; then + assert_not_reached "refs --create unexpectedly succeeded in overwriting an existing prefix!" +fi + +# Force overwriting ctest and check the revision got updated +foo_ctest_rev=$(${CMD_PREFIX} ostree --repo=repo rev-parse foo/ctest) +${CMD_PREFIX} ostree --repo=repo refs foo/ctest --create=ctest --force +assert_ref repo ctest ${foo_ctest_rev} + +# https://github.com/ostreedev/ostree/issues/1285 +# One tool was creating .latest_rsync files in each dir, let's ignore stuff like +# that. +echo '👻' > repo/refs/heads/.spooky_and_hidden +${CMD_PREFIX} ostree --repo=repo refs > refs.txt +assert_not_file_has_content refs.txt 'spooky' +${CMD_PREFIX} ostree --repo=repo refs ctest --create=exampleos/x86_64/standard +echo '👻' > repo/refs/heads/exampleos/x86_64/.further_spooky_and_hidden +${CMD_PREFIX} ostree --repo=repo refs > refs.txt +assert_file_has_content refs.txt 'exampleos/x86_64/standard' +assert_not_file_has_content refs.txt 'spooky' +rm repo/refs/heads/exampleos -rf +echo "ok hidden refs" + +for ref in '.' '-' '.foo' '-bar' '!' '!foo'; do + if ${CMD_PREFIX} ostree --repo=repo refs ctest --create=${ref} 2>err.txt; then + fatal "Created ref ${ref}" + fi + assert_file_has_content err.txt 'Invalid ref' +done +echo "ok invalid refs" + +for ref in 'org.foo.bar/x86_64/standard-blah'; do + ostree --repo=repo refs ctest --create=${ref} + ostree --repo=repo rev-parse ${ref} >/dev/null + ostree --repo=repo refs --delete ${ref} +done +echo "ok valid refs with chars '._-'" + +#Check to see if any uncleaned tmp files were created after failed --create +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create1 +assert_file_has_content refscount.create1 "^5$" + +${CMD_PREFIX} ostree --repo=repo refs ctest --create=ctest-new +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create2 +assert_file_has_content refscount.create2 "^6$" + +#Check to see if a deleted folder can be re-used as the name of a ref +${CMD_PREFIX} ostree --repo=repo refs foo/ctest --delete +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create3 +assert_file_has_content refscount.create3 "^5$" +${CMD_PREFIX} ostree --repo=repo refs ctest --create=foo +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create4 +assert_file_has_content refscount.create4 "^6$" + +#Check if a name for a ref in remote repo can be used locally, and vice versa. +${CMD_PREFIX} ostree --repo=repo commit --branch=origin:remote1 +${CMD_PREFIX} ostree --repo=repo commit --branch=local1 +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create5 +assert_file_has_content refscount.create5 "^8$" + +${CMD_PREFIX} ostree --repo=repo refs origin:remote1 --create=remote1 +${CMD_PREFIX} ostree --repo=repo refs origin:remote1 --create=origin/remote1 +${CMD_PREFIX} ostree --repo=repo refs local1 --create=origin:local1 +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create6 +assert_file_has_content refscount.create6 "^11$" + +#Check that we can list just remote refs +${CMD_PREFIX} ostree --repo=repo refs origin: | wc -l > refscount.create7 +assert_file_has_content refscount.create7 "^2$" # origin:remote1 origin:local1 +#Also support :. for backcompat with flatpak +${CMD_PREFIX} ostree --repo=repo refs origin:. | wc -l > refscount.create8 +assert_file_has_content refscount.create8 "^2$" # origin:remote1 origin:local1 + +echo "ok refs" + +# Test symlinking a ref +${CMD_PREFIX} ostree --repo=repo refs ctest --create=exampleos/x86_64/26/server +${CMD_PREFIX} ostree --repo=repo refs -A exampleos/x86_64/26/server --create=exampleos/x86_64/stable/server +${CMD_PREFIX} ostree --repo=repo summary -u +${CMD_PREFIX} ostree --repo=repo refs > refs.txt +for v in 26 stable; do + assert_file_has_content refs.txt exampleos/x86_64/${v}/server +done +${CMD_PREFIX} ostree --repo=repo refs -A > refs.txt +assert_file_has_content_literal refs.txt 'exampleos/x86_64/stable/server -> exampleos/x86_64/26/server' +assert_not_file_has_content refs.txt '^exampleos/x86_64/26/server' +stable=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/stable/server) +current=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/26/server) +assert_streq "${stable}" "${current}" +${CMD_PREFIX} ostree --repo=repo commit -b exampleos/x86_64/26/server --tree=dir=tree +${CMD_PREFIX} ostree --repo=repo summary -u +newcurrent=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/26/server) +assert_not_streq "${newcurrent}" "${current}" +newstable=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/stable/server) +assert_streq "${newcurrent}" "${newstable}" + +# Test that we can swap the symlink +${CMD_PREFIX} ostree --repo=repo commit -b exampleos/x86_64/27/server --tree=dir=tree +newcurrent=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/27/server) +assert_not_streq "${newcurrent}" "${newstable}" +${CMD_PREFIX} ostree --repo=repo refs -A exampleos/x86_64/27/server --create=exampleos/x86_64/stable/server +newnewstable=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/stable/server) +assert_not_streq "${newnewstable}" "${newstable}" +assert_streq "${newnewstable}" "${newcurrent}" +${CMD_PREFIX} ostree --repo=repo refs > refs.txt +for v in 26 27 stable; do + assert_file_has_content refs.txt exampleos/x86_64/${v}/server +done +${CMD_PREFIX} ostree --repo=repo refs -A > refs.txt +assert_file_has_content_literal refs.txt 'exampleos/x86_64/stable/server -> exampleos/x86_64/27/server' + +# Test that we don't delete a ref having aliases +if ${CMD_PREFIX} ostree --repo=repo refs --delete exampleos/x86_64/27/server; then + assert_not_reached "refs --delete unexpectedly succeeded in deleting a ref containing alias!" +fi + +${CMD_PREFIX} ostree --repo=repo summary -u + +echo "ok ref symlink" + +# https://github.com/ostreedev/ostree/issues/1342 +if ${CMD_PREFIX} ostree --repo=repo refs -A exampleos/x86_64/27/server --create=exampleos:exampleos/x86_64/stable/server 2>err.txt; then + fatal "Created alias ref to remote?" +fi +assert_file_has_content_literal err.txt 'Cannot create alias to remote ref' +echo "ok ref no alias remote" + +if ${CMD_PREFIX} ostree --repo=repo refs -A --create foobar nonexistent 2>err.txt; then + fatal "Created alias to nonexistent ref?" +fi +assert_file_has_content_literal err.txt 'Cannot create alias to non-existent ref' +echo "ok ref no broken alias" diff --git a/tests/test-remote-add-collections.sh b/tests/test-remote-add-collections.sh new file mode 100755 index 0000000..b82a13a --- /dev/null +++ b/tests/test-remote-add-collections.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..1' + +cd ${test_tmpdir} + +# Check that adding a remote with a collection ID results in the ID being in the config. +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add some-remote https://example.com/ --collection-id example-id --gpg-import=${test_tmpdir}/gpghome/key1.asc + +assert_file_has_content repo/config "^collection-id=example-id$" + +echo "ok remote-add-collections" diff --git a/tests/test-remote-add.sh b/tests/test-remote-add.sh new file mode 100755 index 0000000..40a32f5 --- /dev/null +++ b/tests/test-remote-add.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..16' + +setup_test_repository "bare" +$OSTREE remote add origin http://example.com/ostree/gnome +$OSTREE remote show-url origin >/dev/null +echo "ok config" + +$OSTREE remote add --no-sign-verify another http://another.com/repo +$OSTREE remote show-url another >/dev/null +echo "ok remote no gpg-verify" + +if $OSTREE remote add --no-sign-verify another http://another.example.com/anotherrepo 2>err.txt; then + assert_not_reached "Adding duplicate remote unexpectedly succeeded" +fi +echo "ok" + +$OSTREE remote add --if-not-exists --no-sign-verify another http://another.example.com/anotherrepo +$OSTREE remote show-url another >/dev/null +echo "ok" + +$OSTREE remote add --if-not-exists --no-sign-verify another-noexist http://another-noexist.example.com/anotherrepo +$OSTREE remote show-url another-noexist >/dev/null +echo "ok" + +$OSTREE remote list > list.txt +assert_file_has_content list.txt "origin" +assert_file_has_content list.txt "another" +assert_file_has_content list.txt "another-noexist" +assert_not_file_has_content list.txt "http://example\.com/ostree/gnome" +assert_not_file_has_content list.txt "http://another\.com/repo" +assert_not_file_has_content list.txt "http://another-noexist\.example\.com/anotherrepo" +echo "ok remote list" + +$OSTREE remote list --show-urls > list.txt +assert_file_has_content list.txt "origin" +assert_file_has_content list.txt "another" +assert_file_has_content list.txt "another-noexist" +assert_file_has_content list.txt "http://example\.com/ostree/gnome" +assert_file_has_content list.txt "http://another\.com/repo" +assert_file_has_content list.txt "http://another-noexist\.example\.com/anotherrepo" +echo "ok remote list with urls" + +cd ${test_tmpdir} +rm -rf parent-repo +ostree_repo_init parent-repo +$OSTREE config set core.parent ${test_tmpdir}/parent-repo +${CMD_PREFIX} ostree --repo=parent-repo remote add --no-sign-verify parent-remote http://parent-remote.example.com/parent-remote +$OSTREE remote list > list.txt +assert_file_has_content list.txt "origin" +assert_file_has_content list.txt "another" +assert_file_has_content list.txt "another-noexist" +assert_file_has_content list.txt "parent-remote" +echo "ok remote list with parent repo remotes" + +$OSTREE remote delete another +echo "ok remote delete" + +if $OSTREE remote delete nosuchremote 2>err.txt; then + assert_not_reached "Deleting remote unexpectedly succeeded" +fi +assert_file_has_content err.txt "error: " + +$OSTREE remote delete --if-exists nosuchremote +echo "ok" + +if $OSTREE remote show-url nosuchremote 2>/dev/null; then + assert_not_reached "Deleting remote unexpectedly failed" +fi +echo "ok" + +$OSTREE remote delete --if-exists origin +echo "ok" + +if $OSTREE remote show-url origin 2>/dev/null; then + assert_not_reached "Deleting remote unexpectedly failed" +fi +echo "ok" + +$OSTREE remote list > list.txt +assert_not_file_has_content list.txt "origin" +# Can't grep for 'another' because of 'another-noexist' +assert_file_has_content list.txt "another-noexist" +echo "ok remote list remaining" + +# Both --if-not-exists and --force cannot be used +if $OSTREE remote add --if-not-exists --force yetanother http://yetanother.com/repo 2>/dev/null; then + assert_not_reached "Adding remote with --if-not-exists and --force unexpectedly succeeded" +fi +echo "ok remote add fail --if-not-exists and --force" + +# Overwrite with --force +$OSTREE remote add --force another http://another.example.com/anotherrepo +$OSTREE remote list --show-urls > list.txt +assert_file_has_content list.txt "^another \+http://another\.example\.com/anotherrepo$" +echo "ok remote add --force" diff --git a/tests/test-remote-cookies.sh b/tests/test-remote-cookies.sh new file mode 100755 index 0000000..e94a70d --- /dev/null +++ b/tests/test-remote-cookies.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# +# Copyright (C) 2013 Jeremy Whiting +# Copyright (C) 2016 Sjoerd Simons +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +echo '1..4' + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" "" \ + --expected-cookies foo=bar \ + --expected-cookies baz=badger + +assert_fail (){ + if $@; then + (echo 1>&2 "$@ did not fail"; exit 1) + fi +} + +cd ${test_tmpdir} +rm repo -rf +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +# Sanity check the setup, without cookies the pull should fail +assert_fail ${CMD_PREFIX} ostree --repo=repo pull origin main + +echo "ok, setup done" + +# Add 2 cookies, pull should succeed now +${CMD_PREFIX} ostree --repo=repo remote add-cookie origin 127.0.0.1 / foo bar +${CMD_PREFIX} ostree --repo=repo remote add-cookie origin 127.0.0.1 / baz badger +assert_file_has_content repo/origin.cookies.txt foo.*bar +assert_file_has_content repo/origin.cookies.txt baz.*badger +${CMD_PREFIX} ostree --repo=repo pull origin main + +echo "ok, initial cookie pull succeeded" + +# Delete one cookie, if successful pulls will fail again +${CMD_PREFIX} ostree --repo=repo remote delete-cookie origin 127.0.0.1 / baz badger +assert_file_has_content repo/origin.cookies.txt foo.*bar +assert_not_file_has_content repo/origin.cookies.txt baz.*badger +assert_fail ${CMD_PREFIX} ostree --repo=repo pull origin main + +echo "ok, delete succeeded" + +# Re-add the removed cooking and things succeed again, verified the removal +# removed exactly one cookie +${CMD_PREFIX} ostree --repo=repo remote add-cookie origin 127.0.0.1 / baz badger +assert_file_has_content repo/origin.cookies.txt foo.*bar +assert_file_has_content repo/origin.cookies.txt baz.*badger +${CMD_PREFIX} ostree --repo=repo pull origin main + +echo "ok, second cookie pull succeeded" diff --git a/tests/test-remote-gpg-import.sh b/tests/test-remote-gpg-import.sh new file mode 100755 index 0000000..cf13b49 --- /dev/null +++ b/tests/test-remote-gpg-import.sh @@ -0,0 +1,341 @@ +#!/bin/bash +# +# Copyright (C) 2015 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# We don't want OSTREE_GPG_HOME used for these tests. +unset OSTREE_GPG_HOME + +setup_fake_remote_repo1 "archive" + +# Some tests require an appropriate gpg +num_non_gpg_tests=4 +num_gpg_tests=2 +num_tests=$((num_non_gpg_tests + num_gpg_tests)) + +echo "1..${num_tests}" + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo + +#---------------------------------------------- +# Test synchronicity of keyring file and remote +#---------------------------------------------- + +assert_not_has_file repo/R1.trustedkeys.gpg + +${OSTREE} remote add R1 $(cat httpd-address)/ostree/gnomerepo + +assert_not_has_file repo/R1.trustedkeys.gpg + +# Import one valid key ID +${OSTREE} remote gpg-import --keyring ${test_tmpdir}/gpghome/trusted/pubring.gpg R1 ${TEST_GPG_KEYID_1} | grep -o 'Imported [[:digit:]] GPG key' > result +assert_file_has_content result 'Imported 1 GPG key' + +assert_has_file repo/R1.trustedkeys.gpg + +${OSTREE} remote delete R1 + +assert_not_has_file repo/R1.trustedkeys.gpg + +#--------------------------------------- +# Test gpg-import with --keyring option +#--------------------------------------- + +${OSTREE} remote add R1 $(cat httpd-address)/ostree/gnomerepo + +# Import one valid key ID +${OSTREE} remote gpg-import --keyring ${test_tmpdir}/gpghome/trusted/pubring.gpg R1 ${TEST_GPG_KEYID_1} | grep -o 'Imported [[:digit:]] GPG key' > result +assert_file_has_content result 'Imported 1 GPG key' + +# Import multiple valid key IDs +${OSTREE} remote gpg-import --keyring ${test_tmpdir}/gpghome/trusted/pubring.gpg R1 ${TEST_GPG_KEYID_2} ${TEST_GPG_KEYID_3} | grep -o 'Imported [[:digit:]] GPG key' > result +assert_file_has_content result 'Imported 2 GPG key' + +# Import key IDs we already have, make sure they're caught +${OSTREE} remote gpg-import --keyring ${test_tmpdir}/gpghome/trusted/pubring.gpg R1 ${TEST_GPG_KEYID_1} ${TEST_GPG_KEYID_3} | grep -o 'Imported [[:digit:]] GPG key' > result +assert_file_has_content result 'Imported 0 GPG key' + +${OSTREE} remote delete R1 + +${OSTREE} remote add R1 $(cat httpd-address)/ostree/gnomerepo + +# Import all keys from keyring +${OSTREE} remote gpg-import --keyring ${test_tmpdir}/gpghome/trusted/pubring.gpg R1 | grep -o 'Imported [[:digit:]] GPG key' > result +assert_file_has_content result 'Imported 3 GPG key' + +${OSTREE} remote delete R1 + +#------------------------------------- +# Test gpg-import with --stdin option +#------------------------------------- + +${OSTREE} remote add R1 $(cat httpd-address)/ostree/gnomerepo + +# Import ASCII-armored keys thru stdin +cat ${test_tmpdir}/gpghome/key{1,2,3}.asc | ${OSTREE} remote gpg-import --stdin R1 | grep -o 'Imported [[:digit:]] GPG key' > result +assert_file_has_content result 'Imported 3 GPG key' + +${OSTREE} remote delete R1 + +#------------------------------------------------------------ +# Divide keys across multiple remotes, test GPG verification +# For testing purposes the remotes all point to the same URL +# This also tests "remote add" with --gpg-import. +#------------------------------------------------------------ + +${OSTREE} remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc R1 $(cat httpd-address)/ostree/gnomerepo | grep -o 'Imported [[:digit:]] GPG key' > result +assert_file_has_content result 'Imported 1 GPG key' + +${OSTREE} remote add --gpg-import ${test_tmpdir}/gpghome/key2.asc R2 $(cat httpd-address)/ostree/gnomerepo | grep -o 'Imported [[:digit:]] GPG key' > result +assert_file_has_content result 'Imported 1 GPG key' + +${OSTREE} remote add --gpg-import ${test_tmpdir}/gpghome/key3.asc R3 $(cat httpd-address)/ostree/gnomerepo | grep -o 'Imported [[:digit:]] GPG key' > result +assert_file_has_content result 'Imported 1 GPG key' + +# Checkout the "remote" repo so we can add more commits +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo checkout main workdir + +# Sign a new commit with key1 and try pulling from each remote +echo shadow > workdir/blinky +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit -b main -s "Add blinky" --gpg-sign ${TEST_GPG_KEYID_1} --gpg-homedir ${test_tmpdir}/gpghome workdir +if ${OSTREE} pull R2:main >/dev/null 2>&1; then + assert_not_reached "(key1/R2) GPG verification unexpectedly succeeded" +fi +if ${OSTREE} pull R3:main >/dev/null 2>&1; then + assert_not_reached "(key1/R3) GPG verification unexpectedly succeeded" +fi +${OSTREE} pull R1:main >/dev/null + +# Sign a new commit with key2 and try pulling from each remote +echo speedy > workdir/pinky +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit -b main -s "Add pinky" --gpg-sign ${TEST_GPG_KEYID_2} --gpg-homedir ${test_tmpdir}/gpghome workdir +if ${OSTREE} pull R1:main >/dev/null 2>&1; then + assert_not_reached "(key2/R1) GPG verification unexpectedly succeeded" +fi +if ${OSTREE} pull R3:main >/dev/null 2>&1; then + assert_not_reached "(key2/R3) GPG verification unexpectedly succeeded" +fi +${OSTREE} pull R2:main >/dev/null + +# Sign a new commit with key3 and try pulling from each remote +echo bashful > workdir/inky +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit -b main -s "Add inky" --gpg-sign ${TEST_GPG_KEYID_3} --gpg-homedir ${test_tmpdir}/gpghome workdir +if ${OSTREE} pull R1:main >/dev/null 2>&1; then + assert_not_reached "(key3/R1) GPG verification unexpectedly succeeded" +fi +if ${OSTREE} pull R2:main >/dev/null 2>&1; then + assert_not_reached "(key3/R2) GPG verification unexpectedly succeeded" +fi +${OSTREE} pull R3:main >/dev/null + +echo "ok" + +rm repo/refs/remotes/* -rf +${OSTREE} prune --refs-only + +# Test the successful gpgkeypath option +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/key3.asc R4 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R4:main >/dev/null + +# Test gpgkeypath success with multiple keys to try +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/key1.asc,${test_tmpdir}/gpghome/key2.asc,${test_tmpdir}/gpghome/key3.asc R7 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R7:main >/dev/null + +# Test gpgkeypath failure with multiple keys but none in keyring +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/key1.asc,${test_tmpdir}/gpghome/key2.asc R8 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R8:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with different key" +fi +assert_file_has_content err.txt "public key not found" + +# Test gpgkeypath success with directory containing a valid key +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/ R9 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R9:main >/dev/null + +# Test gpgkeypath failure with nonexistent directory +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/INVALIDKEYDIRPATH/ R10 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R10:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key directory" +fi +assert_file_has_content err.txt "INVALIDKEYDIRPATH.*No such file or directory" + +# Test gpgkeypath failure with a directory containing a valid key, and a nonexistent key +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/,${test_tmpdir}/gpghome/INVALIDKEYPATH.asc R11 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R11:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key" +fi +assert_file_has_content err.txt "INVALIDKEYPATH.*No such file or directory" + +# Test gpgkeypath success with a directory containing a valid key, and a key not in keyring +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/,${test_tmpdir}/gpghome/key1.asc R12 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R12:main >/dev/null + +# Test gpgkeypath failure with a nonexistent directory, and a valid key +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/INVALIDKEYDIRPATH/,${test_tmpdir}/gpghome/key3.asc R13 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R13:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key directory" +fi +assert_file_has_content err.txt "INVALIDKEYDIRPATH.*No such file or directory" + +# Test gpgkeypath failure with a nonexistent directory and a nonexistent key +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/INVALIDKEYDIRPATH/,${test_tmpdir}/gpghome/INVALIDKEYPATH.asc R14 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R14:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key" +fi +assert_file_has_content err.txt "INVALIDKEYDIRPATH.*No such file or directory" + +# Test gpgkeypath success for no trailing slash in directory path +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome R15 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R15:main >/dev/null + +# Test gpgkeypath failure with prefixed separator giving an empty path, and a nonexistent key +${OSTREE} remote add --set=gpgkeypath=,${test_tmpdir}/gpghome/INVALIDKEYPATH.asc R16 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R16:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key" +fi +assert_file_has_content err.txt "().*No such file or directory" + +# Test gpgkeypath success with suffixed separator +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/key3.asc, R17 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R17:main >/dev/null + +# Test gpgkeypath success with multiple keys specified, with semicolons +${OSTREE} remote add --set=gpgkeypath="${test_tmpdir}/gpghome/key1.asc;${test_tmpdir}/gpghome/key2.asc;${test_tmpdir}/gpghome/key3.asc" R18 $(cat httpd-address)/ostree/gnomerepo +${OSTREE} pull R18:main >/dev/null + +# Test gpgkeypath failure multiple keys specified, with mix of commas and semicolons +${OSTREE} remote add --set=gpgkeypath="${test_tmpdir}/gpghome/key1.asc,${test_tmpdir}/gpghome/key2.asc;${test_tmpdir}/gpghome/key3.asc" R19 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R19:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with invalid gpgkeypath value" +fi +assert_file_has_content err.txt ".*key value list contains more than one separator" + +rm repo/refs/remotes/* -rf +${OSTREE} prune --refs-only + +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/INVALIDKEYPATH.asc R5 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R5:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with nonexistent key" +fi +assert_file_has_content err.txt "INVALIDKEYPATH.*No such file or directory" + +rm repo/refs/remotes/* -rf +${OSTREE} prune --refs-only + +${OSTREE} remote add --set=gpgkeypath=${test_tmpdir}/gpghome/key2.asc R6 $(cat httpd-address)/ostree/gnomerepo +if ${OSTREE} pull R6:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling with different key" +fi +assert_file_has_content err.txt "public key not found" + +echo "ok" + +# Test deltas with signed commits; this test is a bit +# weird here but this file has separate per-remote keys. +cd ${test_tmpdir} +rm repo/refs/remotes/* -rf +${OSTREE} prune --refs-only +echo $(date) > workdir/testfile-for-deltas-1 +# Sign with keyid 1 for first commit +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main --gpg-sign ${TEST_GPG_KEYID_1} --gpg-homedir ${test_tmpdir}/gpghome workdir +prevrev=$(${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo rev-parse main) +# Pull the previous revision +${OSTREE} pull R1:main +assert_streq $(${OSTREE} rev-parse R1:main) ${prevrev} +# Sign with keyid 2, but use remote r1 +echo $(date) > workdir/testfile-for-deltas-2 +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main --gpg-sign ${TEST_GPG_KEYID_2} --gpg-homedir ${test_tmpdir}/gpghome workdir +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo static-delta generate main +# Summary is signed with key1 +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u --gpg-sign ${TEST_GPG_KEYID_1} --gpg-homedir ${test_tmpdir}/gpghome +newrev=$(${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo rev-parse main) +if ${OSTREE} pull --require-static-deltas R1:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling commit signed with untrusted key" +fi +assert_file_has_content err.txt "public key not found" + +echo "ok gpg untrusted signed commit for delta upgrades" + +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo reset main{,^} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main --gpg-sign ${TEST_GPG_KEYID_1} --gpg-homedir ${test_tmpdir}/gpghome workdir +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo static-delta generate main +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u --gpg-sign ${TEST_GPG_KEYID_1} --gpg-homedir ${test_tmpdir}/gpghome +${OSTREE} pull --require-static-deltas R1:main + +echo "ok gpg trusted signed commit for delta upgrades" + +# Run some more tests if an appropriate gpg is available +GPG=$(which_gpg) +if [ -z "${GPG}" ]; then + # Print a skip message per skipped test + for (( i = 0; i < num_gpg_tests; i++ )); do + echo "ok # SKIP this test requires gpg" + done +else + # Create a commit signed with keyid 1 + echo $(date) > workdir/testfile-for-key-mangling + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main --gpg-sign ${TEST_GPG_KEYID_1} --gpg-homedir ${test_tmpdir}/gpghome workdir + + # Re-add the remote + ${OSTREE} remote delete R1 + ${OSTREE} remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc R1 $(cat httpd-address)/ostree/gnomerepo | grep -o 'Imported [[:digit:]] GPG key' > result + assert_file_has_content result 'Imported 1 GPG key' + + # Expire key 1, wait for it to be expired and import the expired key. Only + # new keys are reported. + ${GPG} --homedir=${test_tmpdir}/gpghome --quick-set-expire ${TEST_GPG_KEYFPR_1} seconds=1 + sleep 2 + ${GPG} --homedir=${test_tmpdir}/gpghome --armor --export ${TEST_GPG_KEYID_1} > ${test_tmpdir}/key1expired.asc + ${OSTREE} remote gpg-import --keyring ${test_tmpdir}/key1expired.asc R1 | grep -o 'Imported [[:digit:]] GPG key' > result + assert_file_has_content result 'Imported 0 GPG key' + + # Pulling should fail since the key is expired + rm repo/refs/remotes/* -rf + ${OSTREE} prune --refs-only + if ${OSTREE} pull R1:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling commit signed with expired key" + fi + assert_file_has_content err.txt "Key expired" + + echo "ok imported expired key" + + # Unexpire keyid 1 and revoke it. Revoking is done by importing the + # pre-generated revocation certificate. + ${GPG} --homedir=${test_tmpdir}/gpghome --quick-set-expire ${TEST_GPG_KEYFPR_1} seconds=0 + ${GPG} --homedir=${TEST_GPG_KEYHOME} --import ${TEST_GPG_KEYHOME}/revocations/key1.rev + ${GPG} --homedir=${test_tmpdir}/gpghome --armor --export ${TEST_GPG_KEYID_1} > ${test_tmpdir}/key1revoked.asc + ${OSTREE} remote gpg-import --keyring ${test_tmpdir}/key1revoked.asc R1 | grep -o 'Imported [[:digit:]] GPG key' > result + assert_file_has_content result 'Imported 0 GPG key' + + # Pulling should fail since the key is revoked + rm repo/refs/remotes/* -rf + ${OSTREE} prune --refs-only + if ${OSTREE} pull R1:main 2>err.txt; then + assert_not_reached "Unexpectedly succeeded at pulling commit signed with revoked key" + fi + assert_file_has_content err.txt "Key revoked" + + echo "ok imported revoked key" +fi diff --git a/tests/test-remote-headers.sh b/tests/test-remote-headers.sh new file mode 100755 index 0000000..a41d087 --- /dev/null +++ b/tests/test-remote-headers.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# +# Copyright (C) 2016 Red Hat, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +echo '1..2' + +. $(dirname $0)/libtest.sh + +V=$($CMD_PREFIX ostree --version | \ + python3 -c 'import sys, yaml; print(yaml.safe_load(sys.stdin)["libostree"]["Version"])') + +setup_fake_remote_repo1 "archive" "" \ + --expected-header foo=bar \ + --expected-header baz=badger \ + --expected-header "User-Agent=libostree/$V dodo/2.15" + +cd ${test_tmpdir} +rm repo -rf +mkdir repo +ostree_repo_init repo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + +# Sanity check the setup, without headers the pull should fail +assert_fail ${CMD_PREFIX} ostree --repo=repo pull origin main + +# without proper User-Agent, the pull should fail +assert_fail ${CMD_PREFIX} ostree --repo=repo pull origin main \ + --http-header foo=bar \ + --http-header baz=badger +assert_fail ${CMD_PREFIX} ostree --repo=repo pull origin main \ + --http-header foo=bar \ + --http-header baz=badger \ + --append-user-agent bar/1.2 + +echo "ok setup done" + +# Now pull should succeed now +${CMD_PREFIX} ostree --repo=repo pull \ + --http-header foo=bar \ + --http-header baz=badger \ + --append-user-agent dodo/2.15 \ + origin main + +echo "ok pull succeeded" diff --git a/tests/test-remotes-config-dir.js b/tests/test-remotes-config-dir.js new file mode 100755 index 0000000..f73a82e --- /dev/null +++ b/tests/test-remotes-config-dir.js @@ -0,0 +1,172 @@ +#!/usr/bin/env gjs +// +// Copyright (C) 2013 Colin Walters +// Copyright (C) 2017 Dan Nicholson +// +// SPDX-License-Identifier: LGPL-2.0+ +// +// 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 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., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; +const OSTree = imports.gi.OSTree; + +function assertEquals(a, b) { + if (a != b) + throw new Error("assertion failed " + JSON.stringify(a) + " == " + JSON.stringify(b)); +} + +function assertNotEquals(a, b) { + if (a == b) + throw new Error("assertion failed " + JSON.stringify(a) + " != " + JSON.stringify(b)); +} + +print('1..9') + +let remotesDir = Gio.File.new_for_path('remotes.d'); +remotesDir.make_directory(null); + +let remoteConfig = GLib.KeyFile.new() +remoteConfig.set_value('remote "foo"', 'url', 'http://foo') + +let remoteConfigFile = remotesDir.get_child('foo.conf') +remoteConfig.save_to_file(remoteConfigFile.get_path()) + +let remoteOptions = GLib.Variant.new('a{sv}', { + 'branches': GLib.Variant.new('as', ['test']), +}); + +// Use the full Repo constructor to set remotes-config-dir +let repoFile = Gio.File.new_for_path('repo'); +let repo = new OSTree.Repo({path: repoFile, + remotes_config_dir: remotesDir.get_path()}); +repo.create(OSTree.RepoMode.ARCHIVE_Z2, null); +repo.open(null); + +// See if the remotes.d remote exists +let remotes = repo.remote_list() +assertNotEquals(remotes.indexOf('foo'), -1); + +print("ok read-remotes-config-dir"); + +// Adding a remote should not go in the remotes.d dir unless this is a +// system repo or add-remotes-config-dir is set to true +repo.remote_add('bar', 'http://bar', remoteOptions, null); +remotes = repo.remote_list() +assertNotEquals(remotes.indexOf('bar'), -1); +assertEquals(remotesDir.get_child('bar.conf').query_exists(null), false); + +print("ok add-not-in-remotes-config-dir"); + +// Removing the remotes.d remote should delete the conf file +repo.remote_delete('foo', null); +remotes = repo.remote_list() +assertEquals(remotes.indexOf('foo'), -1); +assertEquals(remotesDir.get_child('foo.conf').query_exists(null), false); + +print("ok delete-in-remotes-config-dir"); + +// Set add-remotes-config-dir to true and check that a remote gets added +// in the config dir +let repoConfig = repo.copy_config(); +repoConfig.set_boolean('core', 'add-remotes-config-dir', true); +repo.write_config(repoConfig); +repo.reload_config(null); +repo.remote_add('baz', 'http://baz', remoteOptions, null); +remotes = repo.remote_list() +assertNotEquals(remotes.indexOf('baz'), -1); +assertEquals(remotesDir.get_child('baz.conf').query_exists(null), true); + +print("ok add-in-remotes-config-dir"); + +// Trying to set a remote config option via write_config() for a remote +// defined in the config file should succeed +try { + let [, gpg_verify] = repo.remote_get_gpg_verify('bar'); + assertEquals(gpg_verify, true); + repoConfig = repo.copy_config(); + repoConfig.set_boolean('remote "bar"', 'gpg-verify', false); + repo.write_config(repoConfig); + repo.reload_config(null); + [, gpg_verify] = repo.remote_get_gpg_verify('bar'); + assertEquals(gpg_verify, false); + print("ok config-remote-in-config-file-succeeds"); +} catch (e) { + // Skip this test if GPG is not supported + if (!(e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_SUPPORTED))) + throw e; + print("ok config-remote-in-config-file-succeeds # SKIP due build without GPG support"); +} + +// Trying to set a remote config option via write_config() for a remote +// defined in the config dir should fail with G_IO_ERROR_EXISTS +repoConfig = repo.copy_config(); +repoConfig.set_boolean('remote "baz"', 'gpg-verify', false); +try { + if (repo.write_config(repoConfig)) + throw new Error("config of remote in config dir should fail"); +} catch (e) { + if (!(e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS))) + throw e; +} + +print("ok config-remote-in-config-dir-fails"); + +// Replacing a non-existent remote should succeed. This should go in the +// config dir since add-remote-config-dir is set to true above +repo.remote_change(null, OSTree.RepoRemoteChange.REPLACE, + 'nonexistent', 'http://nonexistent', + null, null); +remotes = repo.remote_list(); +assertNotEquals(remotes.indexOf('nonexistent'), -1); +assertEquals(remotesDir.get_child('nonexistent.conf').query_exists(null), true); + +print("ok replace-missing-remote-succeeds"); + +// Test replacing remote options in config dir. This should remove the +// branches setting above +repo.remote_change(null, OSTree.RepoRemoteChange.REPLACE, 'baz', + 'http://baz2', null, null); +remoteConfigFile = remotesDir.get_child('baz.conf'); +remoteConfig = GLib.KeyFile.new(); +remoteConfig.load_from_file(remoteConfigFile.get_path(), + GLib.KeyFileFlags.NONE); +assertEquals(remoteConfig.get_value('remote "baz"', 'url'), 'http://baz2'); +try { + remoteConfig.get_string_list('remote "baz"', 'branches'); + throw new Error('baz remote should not have branches option'); +} catch (e) { + if (!(e.matches(GLib.KeyFileError, GLib.KeyFileError.KEY_NOT_FOUND))) + throw e; +} + +print("ok replace-remote-in-config-dir"); + +// Test replacing remote options in config file. This should remove the +// branches setting above +repo.remote_change(null, OSTree.RepoRemoteChange.REPLACE, 'bar', + 'http://bar2', null, null); +repoConfig = repo.get_config(); +assertEquals(repoConfig.get_value('remote "bar"', 'url'), 'http://bar2'); +try { + repoConfig.get_string_list('remote "bar"', 'branches'); + throw new Error('bar remote should not have branches option'); +} catch (e) { + if (!(e.matches(GLib.KeyFileError, GLib.KeyFileError.KEY_NOT_FOUND))) + throw e; +} + +print("ok replace-remote-in-config-file"); diff --git a/tests/test-repo-finder-avahi.c b/tests/test-repo-finder-avahi.c new file mode 100644 index 0000000..4c9c66e --- /dev/null +++ b/tests/test-repo-finder-avahi.c @@ -0,0 +1,229 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-repo-finder.h" +#include "ostree-repo-finder-avahi.h" +#include "ostree-repo-finder-avahi-private.h" + +/* FIXME: Upstream this */ +G_DEFINE_AUTOPTR_CLEANUP_FUNC (AvahiStringList, avahi_string_list_free) + +/* Test the object constructor works at a basic level. */ +static void +test_repo_finder_avahi_init (void) +{ + g_autoptr(OstreeRepoFinderAvahi) finder = NULL; + g_autoptr(GMainContext) context = NULL; + + /* Default main context. */ + finder = ostree_repo_finder_avahi_new (NULL); + g_clear_object (&finder); + + /* Explicit main context. */ + context = g_main_context_new (); + finder = ostree_repo_finder_avahi_new (context); + g_clear_object (&finder); +} + +/* Test parsing valid and invalid TXT records. */ +static void +test_repo_finder_avahi_txt_records_parse (void) +{ + struct + { + const guint8 *txt; + gsize txt_len; + const gchar *expected_key; /* (nullable) to indicate parse failure */ + const guint8 *expected_value; /* (nullable) to allow for valueless keys */ + gsize expected_value_len; + } + vectors[] = + { + { (const guint8 *) "", 0, NULL, NULL, 0 }, + { (const guint8 *) "\x00", 1, NULL, NULL, 0 }, + { (const guint8 *) "\xff", 1, NULL, NULL, 0 }, + { (const guint8 *) "k\x00", 2, NULL, NULL, 0 }, + { (const guint8 *) "k\xff", 2, NULL, NULL, 0 }, + { (const guint8 *) "=", 1, NULL, NULL, 0 }, + { (const guint8 *) "=value", 6, NULL, NULL, 0 }, + { (const guint8 *) "k=v", 3, "k", (const guint8 *) "v", 1 }, + { (const guint8 *) "key=value", 9, "key", (const guint8 *) "value", 5 }, + { (const guint8 *) "k=v=", 4, "k", (const guint8 *) "v=", 2 }, + { (const guint8 *) "k=", 2, "k", (const guint8 *) "", 0 }, + { (const guint8 *) "k", 1, "k", NULL, 0 }, + { (const guint8 *) "k==", 3, "k", (const guint8 *) "=", 1 }, + { (const guint8 *) "k=\x00\x01\x02", 5, "k", (const guint8 *) "\x00\x01\x02", 3 }, + }; + gsize i; + + for (i = 0; i < G_N_ELEMENTS (vectors); i++) + { + g_autoptr(AvahiStringList) string_list = NULL; + g_autoptr(GHashTable) attributes = NULL; + + g_test_message ("Vector %" G_GSIZE_FORMAT, i); + + string_list = avahi_string_list_add_arbitrary (NULL, vectors[i].txt, vectors[i].txt_len); + + attributes = _ostree_txt_records_parse (string_list); + + if (vectors[i].expected_key != NULL) + { + GBytes *value; + g_autoptr(GBytes) expected_value = NULL; + + g_assert_true (g_hash_table_lookup_extended (attributes, + vectors[i].expected_key, + NULL, + (gpointer *) &value)); + g_assert_cmpuint (g_hash_table_size (attributes), ==, 1); + + if (vectors[i].expected_value != NULL) + { + g_assert_nonnull (value); + expected_value = g_bytes_new_static (vectors[i].expected_value, vectors[i].expected_value_len); + g_assert_true (g_bytes_equal (value, expected_value)); + } + else + { + g_assert_null (value); + } + } + else + { + g_assert_cmpuint (g_hash_table_size (attributes), ==, 0); + } + } +} + +/* Test that the first value for a set of duplicate records is returned. + * See RFC 6763, §6.4. */ +static void +test_repo_finder_avahi_txt_records_duplicates (void) +{ + g_autoptr(AvahiStringList) string_list = NULL; + g_autoptr(GHashTable) attributes = NULL; + GBytes *value; + g_autoptr(GBytes) expected_value = NULL; + + /* Reverse the list before using it, as they are built in reverse order. + * (See the #AvahiStringList documentation.) */ + string_list = avahi_string_list_new ("k=value1", "k=value2", "k=value3", NULL); + string_list = avahi_string_list_reverse (string_list); + attributes = _ostree_txt_records_parse (string_list); + + g_assert_cmpuint (g_hash_table_size (attributes), ==, 1); + value = g_hash_table_lookup (attributes, "k"); + g_assert_nonnull (value); + + expected_value = g_bytes_new_static ("value1", strlen ("value1")); + g_assert_true (g_bytes_equal (value, expected_value)); +} + +/* Test that keys are parsed and looked up case insensitively. + * See RFC 6763, §6.4. */ +static void +test_repo_finder_avahi_txt_records_case_sensitivity (void) +{ + g_autoptr(AvahiStringList) string_list = NULL; + g_autoptr(GHashTable) attributes = NULL; + GBytes *value1, *value2; + g_autoptr(GBytes) expected_value1 = NULL, expected_value2 = NULL; + + /* Reverse the list before using it, as they are built in reverse order. + * (See the #AvahiStringList documentation.) */ + string_list = avahi_string_list_new ("k=value1", + "K=value2", + "KeY2=v", + NULL); + string_list = avahi_string_list_reverse (string_list); + attributes = _ostree_txt_records_parse (string_list); + + g_assert_cmpuint (g_hash_table_size (attributes), ==, 2); + + value1 = g_hash_table_lookup (attributes, "k"); + g_assert_nonnull (value1); + expected_value1 = g_bytes_new_static ("value1", strlen ("value1")); + g_assert_true (g_bytes_equal (value1, expected_value1)); + + g_assert_null (g_hash_table_lookup (attributes, "K")); + + value2 = g_hash_table_lookup (attributes, "key2"); + g_assert_nonnull (value2); + expected_value2 = g_bytes_new_static ("v", 1); + g_assert_true (g_bytes_equal (value2, expected_value2)); + + g_assert_null (g_hash_table_lookup (attributes, "KeY2")); +} + +/* Test that keys which have an empty value can be distinguished from those + * which have no value. See RFC 6763, §6.4. */ +static void +test_repo_finder_avahi_txt_records_empty_and_missing (void) +{ + g_autoptr(AvahiStringList) string_list = NULL; + g_autoptr(GHashTable) attributes = NULL; + GBytes *value1, *value2; + g_autoptr(GBytes) expected_value1 = NULL; + + string_list = avahi_string_list_new ("empty=", + "missing", + NULL); + attributes = _ostree_txt_records_parse (string_list); + + g_assert_cmpuint (g_hash_table_size (attributes), ==, 2); + + value1 = g_hash_table_lookup (attributes, "empty"); + g_assert_nonnull (value1); + expected_value1 = g_bytes_new_static ("", 0); + g_assert_true (g_bytes_equal (value1, expected_value1)); + + g_assert_true (g_hash_table_lookup_extended (attributes, "missing", NULL, (gpointer *) &value2)); + g_assert_null (value2); +} + +int main (int argc, char **argv) +{ + setlocale (LC_ALL, ""); + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/repo-finder-avahi/init", test_repo_finder_avahi_init); + g_test_add_func ("/repo-finder-avahi/txt-records/parse", test_repo_finder_avahi_txt_records_parse); + g_test_add_func ("/repo-finder-avahi/txt-records/duplicates", test_repo_finder_avahi_txt_records_duplicates); + g_test_add_func ("/repo-finder-avahi/txt-records/case-sensitivity", test_repo_finder_avahi_txt_records_case_sensitivity); + g_test_add_func ("/repo-finder-avahi/txt-records/empty-and-missing", test_repo_finder_avahi_txt_records_empty_and_missing); + /* FIXME: Add tests for service processing, probably by splitting the + * code in OstreeRepoFinderAvahi around found_services. */ + + return g_test_run(); +} diff --git a/tests/test-repo-finder-config.c b/tests/test-repo-finder-config.c new file mode 100644 index 0000000..0a2e9e6 --- /dev/null +++ b/tests/test-repo-finder-config.c @@ -0,0 +1,443 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "libostreetest.h" +#include "ostree-autocleanups.h" +#include "ostree-repo-finder.h" +#include "ostree-repo-finder-config.h" + +/* Test fixture. Creates a temporary directory. */ +typedef struct +{ + OstreeRepo *parent_repo; /* owned */ + GLnxTmpDir tmpdir; /* owned */ + GFile *working_dir; /* owned */ +} Fixture; + +static void +setup (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(GError) error = NULL; + + (void)glnx_mkdtemp ("test-repo-finder-config-XXXXXX", 0700, &fixture->tmpdir, &error); + g_assert_no_error (error); + + g_test_message ("Using temporary directory: %s", fixture->tmpdir.path); + + glnx_shutil_mkdir_p_at (fixture->tmpdir.fd, "repo", 0700, NULL, &error); + g_assert_no_error (error); + + fixture->working_dir = g_file_new_for_path (fixture->tmpdir.path); + + fixture->parent_repo = ot_test_setup_repo (NULL, &error); + g_assert_no_error (error); +} + +static void +teardown (Fixture *fixture, + gconstpointer test_data) +{ + /* Recursively remove the temporary directory. */ + (void)glnx_tmpdir_delete (&fixture->tmpdir, NULL, NULL); + + /* The repo also needs its source files to be removed. This is the inverse + * of setup_test_repository() in libtest.sh. */ + int parent_repo_dfd = ostree_repo_get_dfd (fixture->parent_repo); + glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL); + glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL); + + g_clear_object (&fixture->working_dir); + g_clear_object (&fixture->parent_repo); +} + +/* Test the object constructor works at a basic level. */ +static void +test_repo_finder_config_init (void) +{ + g_autoptr(OstreeRepoFinderConfig) finder = NULL; + + /* Default everything. */ + finder = ostree_repo_finder_config_new (); +} + +static void +result_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + GAsyncResult **result_out = user_data; + *result_out = g_object_ref (result); +} + +/* Test that no remotes are found if there are no config files in the refs + * directory. */ +static void +test_repo_finder_config_no_configs (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(OstreeRepoFinderConfig) finder = NULL; + g_autoptr(GMainContext) context = NULL; + g_autoptr(GAsyncResult) result = NULL; + g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */ + g_autoptr(GError) error = NULL; + const OstreeCollectionRef ref1 = { "org.example.Os", "exampleos/x86_64/standard" }; + const OstreeCollectionRef ref2 = { "org.example.Os", "exampleos/x86_64/buildmaster/standard" }; + const OstreeCollectionRef * const refs[] = { &ref1, &ref2, NULL }; + + context = g_main_context_new (); + g_main_context_push_thread_default (context); + + finder = ostree_repo_finder_config_new (); + + ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder), refs, + fixture->parent_repo, NULL, result_cb, &result); + + while (result == NULL) + g_main_context_iteration (context, TRUE); + + results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder), + result, &error); + g_assert_no_error (error); + g_assert_nonnull (results); + g_assert_cmpuint (results->len, ==, 0); + + g_main_context_pop_thread_default (context); +} + +/* Add configuration for a remote named @remote_name, at @remote_uri, with a + * remote collection ID of @collection_id, to the given @repo. */ +static void +assert_create_remote_config (OstreeRepo *repo, + const gchar *remote_name, + const gchar *remote_uri, + const gchar *collection_id) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) options = NULL; + + if (collection_id != NULL) + options = g_variant_new_parsed ("@a{sv} { 'collection-id': <%s> }", + collection_id); + + ostree_repo_remote_add (repo, remote_name, remote_uri, options, NULL, &error); + g_assert_no_error (error); +} + +static gchar *assert_create_remote (Fixture *fixture, + const gchar *collection_id, + ...) G_GNUC_NULL_TERMINATED; + +/* Create a new repository in a temporary directory with its collection ID set + * to @collection_id, and containing the refs given in @... (which must be + * %NULL-terminated). Return the `file://` URI of the new repository. */ +static gchar * +assert_create_remote (Fixture *fixture, + const gchar *collection_id, + ...) +{ + va_list args; + g_autoptr(GError) error = NULL; + const gchar *repo_name = (collection_id != NULL) ? collection_id : "no-collection"; + + glnx_shutil_mkdir_p_at (fixture->tmpdir.fd, repo_name, 0700, NULL, &error); + g_assert_no_error (error); + + g_autoptr(GFile) repo_path = g_file_get_child (fixture->working_dir, repo_name); + g_autoptr(OstreeRepo) repo = ostree_repo_new (repo_path); + ostree_repo_set_collection_id (repo, collection_id, &error); + g_assert_no_error (error); + ostree_repo_create (repo, OSTREE_REPO_MODE_ARCHIVE, NULL, &error); + g_assert_no_error (error); + + /* Set up the refs from @.... */ + va_start (args, collection_id); + + for (const gchar *ref_name = va_arg (args, const gchar *); + ref_name != NULL; + ref_name = va_arg (args, const gchar *)) + { + OstreeCollectionRef collection_ref = { (gchar *) collection_id, (gchar *) ref_name }; + g_autofree gchar *checksum = NULL; + g_autoptr(OstreeMutableTree) mtree = NULL; + g_autoptr(OstreeRepoFile) repo_file = NULL; + + mtree = ostree_mutable_tree_new (); + ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, ".", mtree, NULL, NULL, &error); + g_assert_no_error (error); + ostree_repo_write_mtree (repo, mtree, (GFile **) &repo_file, NULL, &error); + g_assert_no_error (error); + + ostree_repo_write_commit (repo, NULL /* no parent */, ref_name, ref_name, + NULL /* no metadata */, repo_file, &checksum, + NULL, &error); + g_assert_no_error (error); + + if (collection_id != NULL) + ostree_repo_set_collection_ref_immediate (repo, &collection_ref, checksum, NULL, &error); + else + ostree_repo_set_ref_immediate (repo, NULL, ref_name, checksum, NULL, &error); + g_assert_no_error (error); + } + + va_end (args); + + /* Update the summary. */ + ostree_repo_regenerate_summary (repo, NULL /* no metadata */, NULL, &error); + g_assert_no_error (error); + + return g_file_get_uri (repo_path); +} + +/* Test resolving the refs against a collection of config files, which contain + * valid, invalid or duplicate repo information. */ +static void +test_repo_finder_config_mixed_configs (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(OstreeRepoFinderConfig) finder = NULL; + g_autoptr(GMainContext) context = NULL; + g_autoptr(GAsyncResult) result = NULL; + g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */ + g_autoptr(GError) error = NULL; + gsize i; + const OstreeCollectionRef ref0 = { "org.example.Collection0", "exampleos/x86_64/ref0" }; + const OstreeCollectionRef ref1 = { "org.example.Collection0", "exampleos/x86_64/ref1" }; + const OstreeCollectionRef ref2 = { "org.example.Collection1", "exampleos/x86_64/ref1" }; + const OstreeCollectionRef ref3 = { "org.example.Collection1", "exampleos/x86_64/ref2" }; + const OstreeCollectionRef ref4 = { "org.example.Collection2", "exampleos/x86_64/ref3" }; + const OstreeCollectionRef * const refs[] = { &ref0, &ref1, &ref2, &ref3, &ref4, NULL }; + + context = g_main_context_new (); + g_main_context_push_thread_default (context); + + /* Put together various ref configuration files. */ + g_autofree gchar *collection0_uri = assert_create_remote (fixture, "org.example.Collection0", + "exampleos/x86_64/ref0", + "exampleos/x86_64/ref1", + NULL); + g_autofree gchar *collection1_uri = assert_create_remote (fixture, "org.example.Collection1", + "exampleos/x86_64/ref2", + NULL); + g_autofree gchar *no_collection_uri = assert_create_remote (fixture, NULL, + "exampleos/x86_64/ref3", + NULL); + + assert_create_remote_config (fixture->parent_repo, "remote0", collection0_uri, "org.example.Collection0"); + assert_create_remote_config (fixture->parent_repo, "remote1", collection1_uri, "org.example.Collection1"); + assert_create_remote_config (fixture->parent_repo, "remote0-copy", collection0_uri, "org.example.Collection0"); + assert_create_remote_config (fixture->parent_repo, "remote1-bad-copy", collection1_uri, "org.example.NotCollection1"); + assert_create_remote_config (fixture->parent_repo, "remote2", no_collection_uri, NULL); + + finder = ostree_repo_finder_config_new (); + + /* Resolve the refs. */ + ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder), refs, + fixture->parent_repo, NULL, result_cb, &result); + + while (result == NULL) + g_main_context_iteration (context, TRUE); + + results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder), + result, &error); + g_assert_no_error (error); + g_assert_nonnull (results); + g_assert_cmpuint (results->len, ==, 3); + + /* Check that the results are correct: the invalid refs should have been + * ignored, and the valid results canonicalised and deduplicated. */ + for (i = 0; i < results->len; i++) + { + const OstreeRepoFinderResult *result = g_ptr_array_index (results, i); + + if (g_strcmp0 (ostree_remote_get_name (result->remote), "remote0") == 0 || + g_strcmp0 (ostree_remote_get_name (result->remote), "remote0-copy") == 0) + { + g_assert_cmpuint (g_hash_table_size (result->ref_to_checksum), ==, 2); + g_assert_true (g_hash_table_contains (result->ref_to_checksum, &ref0)); + g_assert_true (g_hash_table_contains (result->ref_to_checksum, &ref1)); + g_assert_cmpstr (ostree_remote_get_url (result->remote), ==, collection0_uri); + } + else if (g_strcmp0 (ostree_remote_get_name (result->remote), "remote1") == 0) + { + g_assert_cmpuint (g_hash_table_size (result->ref_to_checksum), ==, 1); + g_assert_true (g_hash_table_contains (result->ref_to_checksum, &ref3)); + g_assert_cmpstr (ostree_remote_get_url (result->remote), ==, collection1_uri); + } + else + { + g_assert_not_reached (); + } + } + + g_main_context_pop_thread_default (context); +} + +/* Test that using ostree_repo_find_remotes_async() works too.*/ +static void +test_repo_finder_config_find_remotes (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(GMainContext) context = NULL; + g_autoptr(GAsyncResult) result = NULL; + g_auto(OstreeRepoFinderResultv) results = NULL; + g_autoptr(GError) error = NULL; + gsize i; + const OstreeCollectionRef ref0 = { "org.example.Collection0", "exampleos/x86_64/ref0" }; + const OstreeCollectionRef ref1 = { "org.example.Collection0", "exampleos/x86_64/ref1" }; + const OstreeCollectionRef ref2 = { "org.example.Collection1", "exampleos/x86_64/ref1" }; + const OstreeCollectionRef ref3 = { "org.example.Collection1", "exampleos/x86_64/ref2" }; + const OstreeCollectionRef ref4 = { "org.example.Collection2", "exampleos/x86_64/ref3" }; + const OstreeCollectionRef * const refs[] = { &ref0, &ref1, &ref2, &ref3, &ref4, NULL }; + OstreeRepoFinder *finders[2] = {NULL, }; + + context = g_main_context_new (); + g_main_context_push_thread_default (context); + + /* Put together various ref configuration files. */ + g_autofree gchar *collection0_uri = assert_create_remote (fixture, "org.example.Collection0", + "exampleos/x86_64/ref0", + "exampleos/x86_64/ref1", + NULL); + g_autofree gchar *collection1_uri = assert_create_remote (fixture, "org.example.Collection1", + "exampleos/x86_64/ref2", + NULL); + g_autofree gchar *no_collection_uri = assert_create_remote (fixture, NULL, + "exampleos/x86_64/ref3", + NULL); + + assert_create_remote_config (fixture->parent_repo, "remote0", collection0_uri, "org.example.Collection0"); + assert_create_remote_config (fixture->parent_repo, "remote1", collection1_uri, "org.example.Collection1"); + assert_create_remote_config (fixture->parent_repo, "remote0-copy", collection0_uri, "org.example.Collection0"); + assert_create_remote_config (fixture->parent_repo, "remote1-bad-copy", collection1_uri, "org.example.NotCollection1"); + assert_create_remote_config (fixture->parent_repo, "remote2", no_collection_uri, NULL); + + finders[0] = OSTREE_REPO_FINDER (ostree_repo_finder_config_new ()); + + /* Resolve the refs. */ + ostree_repo_find_remotes_async (fixture->parent_repo, refs, + NULL, finders, + NULL, NULL, result_cb, &result); + + while (result == NULL) + g_main_context_iteration (context, TRUE); + + results = ostree_repo_find_remotes_finish (fixture->parent_repo, + result, &error); + g_assert_no_error (error); + g_assert_nonnull (results); + g_assert_cmpuint (g_strv_length ((char **) results), ==, 3); + + /* Check that the results are correct: the invalid refs should have been + * ignored, and the valid results canonicalised and deduplicated. */ + for (i = 0; results[i] != NULL; i++) + { + const char *ref0_checksum, *ref1_checksum, *ref2_checksum, *ref3_checksum; + guint64 *ref0_timestamp, *ref1_timestamp, *ref2_timestamp, *ref3_timestamp; + + if (g_strcmp0 (ostree_remote_get_name (results[i]->remote), "remote0") == 0 || + g_strcmp0 (ostree_remote_get_name (results[i]->remote), "remote0-copy") == 0) + { + g_assert_cmpuint (g_hash_table_size (results[i]->ref_to_checksum), ==, 5); + + ref0_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref0); + g_assert_true (ostree_validate_checksum_string (ref0_checksum, NULL)); + + ref1_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref1); + g_assert_true (ostree_validate_checksum_string (ref1_checksum, NULL)); + + ref2_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref2); + g_assert (ref2_checksum == NULL); + + g_assert_cmpuint (g_hash_table_size (results[i]->ref_to_timestamp), ==, 5); + + ref0_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref0); + *ref0_timestamp = GUINT64_FROM_BE (*ref0_timestamp); + g_assert_cmpuint (*ref0_timestamp, >, 0); + + ref1_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref1); + *ref1_timestamp = GUINT64_FROM_BE (*ref1_timestamp); + g_assert_cmpuint (*ref1_timestamp, >, 0); + + ref2_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref2); + *ref2_timestamp = GUINT64_FROM_BE (*ref2_timestamp); + g_assert_cmpuint (*ref2_timestamp, ==, 0); + + g_assert_cmpstr (ostree_remote_get_url (results[i]->remote), ==, collection0_uri); + } + else if (g_strcmp0 (ostree_remote_get_name (results[i]->remote), "remote1") == 0) + { + g_assert_cmpuint (g_hash_table_size (results[i]->ref_to_checksum), ==, 5); + + ref3_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref3); + g_assert_true (ostree_validate_checksum_string (ref3_checksum, NULL)); + + ref0_checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ref0); + g_assert (ref0_checksum == NULL); + + g_assert_cmpuint (g_hash_table_size (results[i]->ref_to_timestamp), ==, 5); + + ref3_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref3); + *ref3_timestamp = GUINT64_FROM_BE (*ref3_timestamp); + g_assert_cmpuint (*ref3_timestamp, >, 0); + + ref0_timestamp = g_hash_table_lookup (results[i]->ref_to_timestamp, &ref0); + *ref0_timestamp = GUINT64_FROM_BE (*ref0_timestamp); + g_assert_cmpuint (*ref0_timestamp, ==, 0); + + g_assert_cmpstr (ostree_remote_get_url (results[i]->remote), ==, collection1_uri); + } + else + { + g_assert_not_reached (); + } + } + + g_main_context_pop_thread_default (context); +} + +int main (int argc, char **argv) +{ + setlocale (LC_ALL, ""); + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/repo-finder-config/init", test_repo_finder_config_init); + g_test_add ("/repo-finder-config/no-configs", Fixture, NULL, setup, + test_repo_finder_config_no_configs, teardown); + g_test_add ("/repo-finder-config/mixed-configs", Fixture, NULL, setup, + test_repo_finder_config_mixed_configs, teardown); + g_test_add ("/repo-finder-config/find-remotes", Fixture, NULL, setup, + test_repo_finder_config_find_remotes, teardown); + + return g_test_run(); +} diff --git a/tests/test-repo-finder-mount-integration.sh b/tests/test-repo-finder-mount-integration.sh new file mode 100755 index 0000000..9ecc4cd --- /dev/null +++ b/tests/test-repo-finder-mount-integration.sh @@ -0,0 +1,133 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Authors: +# - Philip Withnall + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +SUDO="sudo --non-interactive" + +# Skip the test if a well-known USB stick is not available. +# To run the test, you must have a throwaway partition on a USB stick (doesn’t +# matter how it’s formatted, as the test will reformat it), and must set +# MOUNT_INTEGRATION_DEV to that partition. For example, +# MOUNT_INTEGRATION_DEV=/dev/sdb1. For safety, the test will be skipped if the +# partition is already mounted. +# +# FIXME: We could potentially automate this in future if there’s a way to trick +# GIO into treating an arbitrary partition (such as a loopback device of our +# creation) as removable. + +if ! [ -b "${MOUNT_INTEGRATION_DEV:-}" ]; then + skip "Test needs a disposable USB stick passed in as MOUNT_INTEGRATION_DEV" +fi + +# Sanity check that the given device is not already mounted, to try and avoid +# hosing the system. +if mount | grep -q "${MOUNT_INTEGRATION_DEV}"; then + skip "${MOUNT_INTEGRATION_DEV} must not be mounted already" +fi + +_mount_cleanup () { + ${SUDO} umount "${MOUNT_INTEGRATION_DEV}" || true +} + +case "${TEST_SKIP_CLEANUP:-}" in + no|"") + libtest_exit_cmds+=(_mount_cleanup) + ;; + err) + trap _mount_cleanup ERR + ;; +esac + +echo "1..3" + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo --collection-id org.example.Collection1 + +mkdir -p tree/root +touch tree/root/a + +# Add a few commits +seq 5 | while read i; do + echo a >> tree/root/a + ${CMD_PREFIX} ostree --repo=repo commit --branch=test-$i -m test -s test --gpg-homedir="${TEST_GPG_KEYHOME}" --gpg-sign="${TEST_GPG_KEYID_1}" tree +done + +${CMD_PREFIX} ostree --repo=repo summary --update --gpg-homedir="${TEST_GPG_KEYHOME}" --gpg-sign="${TEST_GPG_KEYID_1}" +${CMD_PREFIX} ostree --repo=repo rev-parse test-1 > ref1-checksum + +# Pull into a ‘local’ repository, to more accurately represent the situation of +# creating a USB stick from your local machine. +mkdir local-repo +ostree_repo_init local-repo +${CMD_PREFIX} ostree --repo=local-repo remote add remote1 file://$(pwd)/repo --collection-id org.example.Collection1 --gpg-import="${test_tmpdir}/gpghome/key1.asc" +${CMD_PREFIX} ostree --repo=local-repo pull remote1 test-1 test-2 test-3 test-4 test-5 + +for fs_type in ext4 vfat; do + # Prepare a USB stick containing some of the refs on the given file system. + if [ "$fs_type" = "ext4" ]; then + fs_options="-F -E root_owner=$(id -u):$(id -g)" + else + fs_options= + fi + ${SUDO} mkfs.$fs_type $fs_options "${MOUNT_INTEGRATION_DEV}" > /dev/null + usb_mount=$(udisksctl mount --block-device "${MOUNT_INTEGRATION_DEV}" --filesystem-type $fs_type | sed -n "s/^Mounted .* at \(.*\)\.$/\1/p") + + ${CMD_PREFIX} ostree --repo=local-repo create-usb "${usb_mount}" org.example.Collection1 test-1 org.example.Collection1 test-2 + + assert_has_dir "${usb_mount}"/.ostree/repo + ${CMD_PREFIX} ostree --repo="${usb_mount}"/.ostree/repo refs --collections > dest-refs + assert_file_has_content dest-refs "^(org\.example\.Collection1, test-1)$" + assert_file_has_content dest-refs "^(org\.example\.Collection1, test-2)$" + assert_not_file_has_content dest-refs "^(org\.example\.Collection1, test-3)$" + assert_has_file "${usb_mount}"/.ostree/repo/summary + + # Pull into a second local repository (theoretically, a separate computer). + mkdir peer-repo_$fs_type + ostree_repo_init peer-repo_$fs_type + ${CMD_PREFIX} ostree --repo=peer-repo_$fs_type remote add remote1 file://just-here-for-the-keyring --collection-id org.example.Collection1 --gpg-import="${test_tmpdir}/gpghome/key1.asc" + + ${CMD_PREFIX} ostree --repo=peer-repo_$fs_type find-remotes --finders=mount org.example.Collection1 test-1 > find-results + assert_not_file_has_content find-results "^No results\.$" + assert_file_has_content find-results "^Result 0: file://${usb_mount}" + assert_file_has_content find-results "(org\.example\.Collection1, test-1) = $(cat ref1-checksum)$" + + ${CMD_PREFIX} ostree --repo=peer-repo_$fs_type find-remotes --finders=mount --pull org.example.Collection1 test-1 > pull-results + assert_file_has_content pull-results "^Pulled 1/1 refs successfully\.$" + + ${CMD_PREFIX} ostree --repo=peer-repo_$fs_type refs --collections > refs + assert_file_has_content refs "^(org\.example\.Collection1, test-1)$" + + ${SUDO} umount "${MOUNT_INTEGRATION_DEV}" + + echo "ok end-to-end USB on ${fs_type}" +done + +# Check the two repositories are identical. +diff -ur peer-repo_ext4 peer-repo_vfat + +echo "ok end-to-end USB repositories are identical" diff --git a/tests/test-repo-finder-mount.c b/tests/test-repo-finder-mount.c new file mode 100644 index 0000000..af2f5e0 --- /dev/null +++ b/tests/test-repo-finder-mount.c @@ -0,0 +1,570 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "libostreetest.h" +#include "ostree-autocleanups.h" +#include "ostree-remote-private.h" +#include "ostree-repo-finder.h" +#include "ostree-repo-finder-mount.h" +#include "ostree-types.h" +#include "test-mock-gio.h" + +/* Test fixture. Creates a temporary directory and repository. */ +typedef struct +{ + OstreeRepo *parent_repo; + GLnxTmpDir tmpdir; /* owned */ + GFile *working_dir; /* Points at tmpdir */ +} Fixture; + +static void +setup (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(GError) error = NULL; + + (void)glnx_mkdtemp ("test-repo-finder-mount-XXXXXX", 0700, &fixture->tmpdir, &error); + g_assert_no_error (error); + + g_test_message ("Using temporary directory: %s", fixture->tmpdir.path); + + glnx_shutil_mkdir_p_at (fixture->tmpdir.fd, "repo", 0700, NULL, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + g_clear_error (&error); + g_assert_no_error (error); + + /* Realpath since at least coretoolbox makes /tmp a symlink to /host/tmp */ + g_autofree char *tmpdir_real_path = realpath (fixture->tmpdir.path, NULL); + fixture->working_dir = g_file_new_for_path (tmpdir_real_path); + + fixture->parent_repo = ot_test_setup_repo (NULL, &error); + g_assert_no_error (error); +} + +static void +teardown (Fixture *fixture, + gconstpointer test_data) +{ + /* Recursively remove the temporary directory. */ + (void)glnx_tmpdir_delete (&fixture->tmpdir, NULL, NULL); + + /* The repo also needs its source files to be removed. This is the inverse + * of setup_test_repository() in libtest.sh. */ + int parent_repo_dfd = ostree_repo_get_dfd (fixture->parent_repo); + glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL); + glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL); + + g_clear_object (&fixture->working_dir); + g_clear_object (&fixture->parent_repo); +} + +/* Test the object constructor works at a basic level. */ +static void +test_repo_finder_mount_init (void) +{ + g_autoptr(OstreeRepoFinderMount) finder = NULL; + g_autoptr(GVolumeMonitor) monitor = NULL; + + /* Default #GVolumeMonitor. */ + finder = ostree_repo_finder_mount_new (NULL); + g_clear_object (&finder); + + /* Explicit #GVolumeMonitor. */ + monitor = ostree_mock_volume_monitor_new (NULL, NULL); + finder = ostree_repo_finder_mount_new (monitor); + g_clear_object (&finder); +} + +static void +result_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + GAsyncResult **result_out = user_data; + *result_out = g_object_ref (result); +} + +/* Test that no remotes are found if the #GVolumeMonitor returns no mounts. */ +static void +test_repo_finder_mount_no_mounts (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(OstreeRepoFinderMount) finder = NULL; + g_autoptr(GVolumeMonitor) monitor = NULL; + g_autoptr(GMainContext) context = NULL; + g_autoptr(GAsyncResult) result = NULL; + g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */ + g_autoptr(GError) error = NULL; + const OstreeCollectionRef ref1 = { "org.example.Collection1", "exampleos/x86_64/standard" }; + const OstreeCollectionRef ref2 = { "org.example.Collection1", "exampleos/x86_64/buildmaster/standard" }; + const OstreeCollectionRef ref3 = { "org.example.Collection2", "exampleos/x86_64/standard" }; + const OstreeCollectionRef ref4 = { "org.example.Collection2", "exampleos/arm64/standard" }; + const OstreeCollectionRef * const refs[] = { &ref1, &ref2, &ref3, &ref4, NULL }; + + context = g_main_context_new (); + g_main_context_push_thread_default (context); + + monitor = ostree_mock_volume_monitor_new (NULL, NULL); + finder = ostree_repo_finder_mount_new (monitor); + + ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder), refs, + fixture->parent_repo, + NULL, result_cb, &result); + + while (result == NULL) + g_main_context_iteration (context, TRUE); + + results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder), + result, &error); + g_assert_no_error (error); + g_assert_nonnull (results); + g_assert_cmpuint (results->len, ==, 0); + + g_main_context_pop_thread_default (context); +} + +/* Create a .ostree/repos.d directory under the given @mount_root, or abort. */ +static gboolean +assert_create_repos_dir (Fixture *fixture, + const gchar *mount_root_name, + int *out_repos_dfd, + GMount **out_mount) +{ + glnx_autofd int repos_dfd = -1; + g_autoptr(GError) error = NULL; + + g_autofree gchar *path = g_build_filename (mount_root_name, ".ostree", "repos.d", NULL); + glnx_shutil_mkdir_p_at_open (fixture->tmpdir.fd, path, 0700, &repos_dfd, NULL, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + g_clear_error (&error); + g_assert_no_error (error); + + *out_repos_dfd = glnx_steal_fd (&repos_dfd); + g_autoptr(GFile) mount_root = g_file_get_child (fixture->working_dir, mount_root_name); + *out_mount = G_MOUNT (ostree_mock_mount_new (mount_root_name, mount_root)); + + return TRUE; +} + +/* Create a new repository in @repo_dir with its collection ID unset, and + * containing the refs given in @... (which must be %NULL-terminated). Each + * #OstreeCollectionRef in @... is followed by a gchar** return address for the + * checksum committed for that ref. Return the new repository. */ +static OstreeRepo * +assert_create_remote_va (Fixture *fixture, + GFile *repo_dir, + va_list args) +{ + g_autoptr(GError) error = NULL; + + g_autoptr(OstreeRepo) repo = ostree_repo_new (repo_dir); + ostree_repo_create (repo, OSTREE_REPO_MODE_ARCHIVE, NULL, &error); + g_assert_no_error (error); + + /* Set up the refs from @.... */ + for (const OstreeCollectionRef *ref = va_arg (args, const OstreeCollectionRef *); + ref != NULL; + ref = va_arg (args, const OstreeCollectionRef *)) + { + g_autofree gchar *checksum = NULL; + g_autoptr(OstreeMutableTree) mtree = NULL; + g_autoptr(OstreeRepoFile) repo_file = NULL; + gchar **out_checksum = va_arg (args, gchar **); + + mtree = ostree_mutable_tree_new (); + ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, ".", mtree, NULL, NULL, &error); + g_assert_no_error (error); + ostree_repo_write_mtree (repo, mtree, (GFile **) &repo_file, NULL, &error); + g_assert_no_error (error); + + ostree_repo_write_commit (repo, NULL /* no parent */, ref->ref_name, ref->ref_name, + NULL /* no metadata */, repo_file, &checksum, + NULL, &error); + g_assert_no_error (error); + + if (ref->collection_id != NULL) + ostree_repo_set_collection_ref_immediate (repo, ref, checksum, NULL, &error); + else + ostree_repo_set_ref_immediate (repo, NULL, ref->ref_name, checksum, NULL, &error); + g_assert_no_error (error); + + if (out_checksum != NULL) + *out_checksum = g_steal_pointer (&checksum); + } + + /* Update the summary. */ + ostree_repo_regenerate_summary (repo, NULL /* no metadata */, NULL, &error); + g_assert_no_error (error); + + return g_steal_pointer (&repo); +} + +static OstreeRepo * +assert_create_repo_dir (Fixture *fixture, + int repos_dfd, + GMount *repos_mount, + const char *repo_name, + gchar **out_uri, + ...) G_GNUC_NULL_TERMINATED; + +/* Create a @repo_name directory under the given @repos_dfd, or abort. Create a + * new repository in it with the refs given in @..., as per + * assert_create_remote_va(). Return the URI of the repository. */ +static OstreeRepo * +assert_create_repo_dir (Fixture *fixture, + int repos_dfd, + GMount *repos_mount, + const char *repo_name, + gchar **out_uri, + ...) +{ + glnx_autofd int ref_dfd = -1; + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GError) error = NULL; + va_list args; + + glnx_shutil_mkdir_p_at_open (repos_dfd, repo_name, 0700, &ref_dfd, NULL, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + g_clear_error (&error); + g_assert_no_error (error); + + g_autoptr(GFile) mount_root = g_mount_get_root (repos_mount); + g_autoptr(GFile) repos_dir = g_file_get_child (mount_root, ".ostree/repos.d"); + g_autoptr(GFile) repo_dir = g_file_get_child (repos_dir, repo_name); + + va_start (args, out_uri); + repo = assert_create_remote_va (fixture, repo_dir, args); + va_end (args); + + *out_uri = g_file_get_uri (repo_dir); + + return g_steal_pointer (&repo); +} + +/* Create a @repo_name symlink under the given @repos_dfd, pointing to + * @symlink_target_path, or abort. */ +static void +assert_create_repo_symlink (int repos_dfd, + const char *repo_name, + const char *symlink_target_path) +{ + if (TEMP_FAILURE_RETRY (symlinkat (symlink_target_path, repos_dfd, repo_name)) != 0) + { + g_autoptr(GError) error = NULL; + glnx_throw_errno_prefix (&error, "symlinkat"); + g_assert_no_error (error); + } +} + +/* Add configuration for a remote named @remote_name, at @remote_uri, with a + * remote collection ID of @collection_id, to the given @repo. */ +static void +assert_create_remote_config (OstreeRepo *repo, + const gchar *remote_name, + const gchar *remote_uri, + const gchar *collection_id) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) options = NULL; + + if (collection_id != NULL) + options = g_variant_new_parsed ("@a{sv} { 'collection-id': <%s> }", + collection_id); + + ostree_repo_remote_add (repo, remote_name, remote_uri, options, NULL, &error); + g_assert_no_error (error); +} + +/* Test resolving the refs against a collection of mock volumes, some of which + * are mounted, some of which are removable, some of which contain valid or + * invalid repo information on the file system, etc. */ +static void +test_repo_finder_mount_mixed_mounts (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(OstreeRepoFinderMount) finder = NULL; + g_autoptr(GVolumeMonitor) monitor = NULL; + g_autoptr(GMainContext) context = NULL; + g_autoptr(GAsyncResult) result = NULL; + g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */ + g_autoptr(GError) error = NULL; + g_autoptr(GList) mounts = NULL; /* (element-type OstreeMockMount) */ + g_autoptr(GMount) non_removable_mount = NULL; + g_autoptr(GMount) no_repos_mount = NULL; + g_autoptr(GMount) repo1_mount = NULL; + g_autoptr(GMount) repo2_mount = NULL; + g_autoptr(GFile) non_removable_root = NULL; + glnx_autofd int no_repos_repos = -1; + glnx_autofd int repo1_repos = -1; + glnx_autofd int repo2_repos = -1; + g_autoptr(OstreeRepo) repo1_repo_a = NULL, repo1_repo_b = NULL; + g_autoptr(OstreeRepo) repo2_repo_a = NULL; + g_autofree gchar *repo1_repo_a_uri = NULL, *repo1_repo_b_uri = NULL; + g_autofree gchar *repo2_repo_a_uri = NULL; + g_autofree gchar *repo1_ref0_checksum = NULL, *repo1_ref1_checksum = NULL, *repo1_ref2_checksum = NULL; + g_autofree gchar *repo2_ref0_checksum = NULL, *repo2_ref1_checksum = NULL, *repo2_ref2_checksum = NULL; + g_autofree gchar *repo1_ref5_checksum = NULL, *repo2_ref3_checksum = NULL; + gsize i; + const OstreeCollectionRef ref0 = { "org.example.Collection1", "exampleos/x86_64/ref0" }; + const OstreeCollectionRef ref1 = { "org.example.Collection1", "exampleos/x86_64/ref1" }; + const OstreeCollectionRef ref2 = { "org.example.Collection1", "exampleos/x86_64/ref2" }; + const OstreeCollectionRef ref3 = { "org.example.Collection1", "exampleos/x86_64/ref3" }; + const OstreeCollectionRef ref4 = { "org.example.UnconfiguredCollection", "exampleos/x86_64/ref4" }; + const OstreeCollectionRef ref5 = { "org.example.Collection3", "exampleos/x86_64/ref0" }; + const OstreeCollectionRef * const refs[] = { &ref0, &ref1, &ref2, &ref3, &ref4, &ref5, NULL }; + + context = g_main_context_new (); + g_main_context_push_thread_default (context); + + /* Build the various mock drives/volumes/mounts, and some repositories with + * refs within them. We use "/" under the assumption that it’s on a separate + * file system from /tmp, so it’s an example of a symlink pointing outside + * its mount point. */ + non_removable_root = g_file_get_child (fixture->working_dir, "non-removable-mount"); + non_removable_mount = G_MOUNT (ostree_mock_mount_new ("non-removable", non_removable_root)); + + assert_create_repos_dir (fixture, "no-repos-mount", &no_repos_repos, &no_repos_mount); + + assert_create_repos_dir (fixture, "repo1-mount", &repo1_repos, &repo1_mount); + repo1_repo_a = assert_create_repo_dir (fixture, repo1_repos, repo1_mount, "repo1-repo-a", &repo1_repo_a_uri, + refs[0], &repo1_ref0_checksum, + refs[2], &repo1_ref2_checksum, + refs[5], &repo1_ref5_checksum, + NULL); + repo1_repo_b = assert_create_repo_dir (fixture, repo1_repos, repo1_mount, "repo1-repo-b", &repo1_repo_b_uri, + refs[1], &repo1_ref1_checksum, + NULL); + assert_create_repo_symlink (repo1_repos, "repo1-repo-a-alias", "repo1-repo-a"); + + assert_create_repos_dir (fixture, "repo2-mount", &repo2_repos, &repo2_mount); + repo2_repo_a = assert_create_repo_dir (fixture, repo2_repos, repo2_mount, "repo2-repo-a", &repo2_repo_a_uri, + refs[0], &repo2_ref0_checksum, + refs[1], &repo2_ref1_checksum, + refs[2], &repo2_ref2_checksum, + refs[3], &repo2_ref3_checksum, + NULL); + assert_create_repo_symlink (repo2_repos, "repo2-repo-a-alias", "repo2-repo-a"); + assert_create_repo_symlink (repo2_repos, "dangling-symlink", "repo2-repo-b"); + assert_create_repo_symlink (repo2_repos, "root", "/"); + + mounts = g_list_prepend (mounts, non_removable_mount); + mounts = g_list_prepend (mounts, no_repos_mount); + mounts = g_list_prepend (mounts, repo1_mount); + mounts = g_list_prepend (mounts, repo2_mount); + + monitor = ostree_mock_volume_monitor_new (mounts, NULL); + finder = ostree_repo_finder_mount_new (monitor); + + assert_create_remote_config (fixture->parent_repo, "remote1", "https://nope1", "org.example.Collection1"); + assert_create_remote_config (fixture->parent_repo, "remote2", "https://nope2", "org.example.Collection2"); + /* don’t configure org.example.UnconfiguredCollection */ + assert_create_remote_config (fixture->parent_repo, "remote3", "https://nope3", "org.example.Collection3"); + + /* Resolve the refs. */ + ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder), refs, + fixture->parent_repo, + NULL, result_cb, &result); + + while (result == NULL) + g_main_context_iteration (context, TRUE); + + results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder), + result, &error); + g_assert_no_error (error); + g_assert_nonnull (results); + g_assert_cmpuint (results->len, ==, 4); + + /* Check that the results are correct: the invalid refs should have been + * ignored, and the valid results canonicalised and deduplicated. */ + for (i = 0; i < results->len; i++) + { + g_autofree gchar *uri = NULL; + const gchar *keyring; + const OstreeRepoFinderResult *result = g_ptr_array_index (results, i); + + uri = g_key_file_get_string (result->remote->options, result->remote->group, "url", &error); + g_assert_no_error (error); + keyring = result->remote->keyring; + + if (g_strcmp0 (uri, repo1_repo_a_uri) == 0 && + g_strcmp0 (keyring, "remote1.trustedkeys.gpg") == 0) + { + g_assert_cmpuint (g_hash_table_size (result->ref_to_checksum), ==, 2); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, refs[0]), ==, repo1_ref0_checksum); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, refs[2]), ==, repo1_ref2_checksum); + } + else if (g_strcmp0 (uri, repo1_repo_a_uri) == 0 && + g_strcmp0 (keyring, "remote3.trustedkeys.gpg") == 0) + { + g_assert_cmpuint (g_hash_table_size (result->ref_to_checksum), ==, 1); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, refs[5]), ==, repo1_ref5_checksum); + } + else if (g_strcmp0 (uri, repo1_repo_b_uri) == 0 && + g_strcmp0 (keyring, "remote1.trustedkeys.gpg") == 0) + { + g_assert_cmpuint (g_hash_table_size (result->ref_to_checksum), ==, 1); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, refs[1]), ==, repo1_ref1_checksum); + } + else if (g_strcmp0 (uri, repo2_repo_a_uri) == 0 && + g_strcmp0 (keyring, "remote1.trustedkeys.gpg") == 0) + { + g_assert_cmpuint (g_hash_table_size (result->ref_to_checksum), ==, 4); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, refs[0]), ==, repo2_ref0_checksum); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, refs[1]), ==, repo2_ref1_checksum); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, refs[2]), ==, repo2_ref2_checksum); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, refs[3]), ==, repo2_ref3_checksum); + } + else + { + g_error ("Unknown result ‘%s’ with keyring ‘%s’", + result->remote->name, result->remote->keyring); + } + } + + g_main_context_pop_thread_default (context); +} + +/* Test resolving the refs against a mock volume which contains two repositories + * in the default repository paths ostree/repo and .ostree/repo, to check that + * those paths are read */ +static void +test_repo_finder_mount_well_known (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(OstreeRepoFinderMount) finder = NULL; + g_autoptr(GVolumeMonitor) monitor = NULL; + g_autoptr(GMainContext) context = NULL; + g_autoptr(GAsyncResult) result = NULL; + g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */ + g_autoptr(GError) error = NULL; + g_autoptr(GList) mounts = NULL; /* (element-type OstreeMockMount) */ + g_autoptr(GMount) mount = NULL; + glnx_autofd int repos = -1; + g_autoptr(OstreeRepo) repo_a = NULL, repo_b = NULL; + g_autofree gchar *repo_a_uri = NULL, *repo_b_uri = NULL; + g_autofree gchar *ref_a_checksum = NULL, *ref_b_checksum = NULL; + gsize i; + const OstreeCollectionRef ref_a = { "org.example.Collection1", "refA" }; + const OstreeCollectionRef ref_b = { "org.example.Collection2", "refB" }; + const OstreeCollectionRef * const refs[] = { &ref_a, &ref_b, NULL }; + + context = g_main_context_new (); + g_main_context_push_thread_default (context); + + /* Build the various mock drives/volumes/mounts, and some repositories with + * refs within them. We use "/" under the assumption that it’s on a separate + * file system from /tmp, so it’s an example of a symlink pointing outside + * its mount point. */ + assert_create_repos_dir (fixture, "mount", &repos, &mount); + repo_a = assert_create_repo_dir (fixture, repos, mount, "../../ostree/repo", &repo_a_uri, + &ref_a, &ref_a_checksum, + NULL); + repo_b = assert_create_repo_dir (fixture, repos, mount, "../../.ostree/repo", &repo_b_uri, + &ref_b, &ref_b_checksum, + NULL); + assert_create_repo_symlink (repos, "repo-a-alias", "../../ostree/repo"); + + mounts = g_list_prepend (mounts, mount); + + monitor = ostree_mock_volume_monitor_new (mounts, NULL); + finder = ostree_repo_finder_mount_new (monitor); + + assert_create_remote_config (fixture->parent_repo, "remote1", "https://nope1", "org.example.Collection1"); + assert_create_remote_config (fixture->parent_repo, "remote2", "https://nope2", "org.example.Collection2"); + + /* Resolve the refs. */ + ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder), refs, + fixture->parent_repo, + NULL, result_cb, &result); + + while (result == NULL) + g_main_context_iteration (context, TRUE); + + results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder), + result, &error); + g_assert_no_error (error); + g_assert_nonnull (results); + g_assert_cmpuint (results->len, ==, 2); + + /* Check that the results are correct: the valid results canonicalised and + * deduplicated. */ + for (i = 0; i < results->len; i++) + { + g_autofree gchar *uri = NULL; + const gchar *keyring; + const OstreeRepoFinderResult *result = g_ptr_array_index (results, i); + + uri = g_key_file_get_string (result->remote->options, result->remote->group, "url", &error); + g_assert_no_error (error); + keyring = result->remote->keyring; + + if (g_strcmp0 (uri, repo_a_uri) == 0 && + g_strcmp0 (keyring, "remote1.trustedkeys.gpg") == 0) + { + g_assert_cmpuint (g_hash_table_size (result->ref_to_checksum), ==, 1); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, &ref_a), ==, ref_a_checksum); + } + else if (g_strcmp0 (uri, repo_b_uri) == 0 && + g_strcmp0 (keyring, "remote2.trustedkeys.gpg") == 0) + { + g_assert_cmpuint (g_hash_table_size (result->ref_to_checksum), ==, 1); + g_assert_cmpstr (g_hash_table_lookup (result->ref_to_checksum, &ref_b), ==, ref_b_checksum); + } + else + { + g_test_message ("Unknown result ‘%s’ with keyring ‘%s’.", + result->remote->name, result->remote->keyring); + g_assert_not_reached (); + } + } + + g_main_context_pop_thread_default (context); +} + +int main (int argc, char **argv) +{ + setlocale (LC_ALL, ""); + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/repo-finder-mount/init", test_repo_finder_mount_init); + g_test_add ("/repo-finder-mount/no-mounts", Fixture, NULL, setup, + test_repo_finder_mount_no_mounts, teardown); +#ifndef OSTREE_DISABLE_GPGME + /*`ostree_repo_resolve_keyring_for_collection()` fail the tests if no GPG support is compiled in. */ + g_test_add ("/repo-finder-mount/mixed-mounts", Fixture, NULL, setup, + test_repo_finder_mount_mixed_mounts, teardown); + g_test_add ("/repo-finder-mount/well-known", Fixture, NULL, setup, + test_repo_finder_mount_well_known, teardown); +#endif /* OSTREE_DISABLE_GPGME */ + + return g_test_run(); +} diff --git a/tests/test-repo.c b/tests/test-repo.c new file mode 100644 index 0000000..9857228 --- /dev/null +++ b/tests/test-repo.c @@ -0,0 +1,218 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ostree-autocleanups.h" +#include "ostree-types.h" + +/* Test fixture. Creates a temporary directory. */ +typedef struct +{ + GLnxTmpDir tmpdir; /* (owned) */ +} Fixture; + +static void +setup (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(GError) error = NULL; + + (void) glnx_mkdtemp ("test-repo-XXXXXX", 0700, &fixture->tmpdir, &error); + g_assert_no_error (error); + + g_test_message ("Using temporary directory: %s", fixture->tmpdir.path); +} + +static void +teardown (Fixture *fixture, + gconstpointer test_data) +{ + /* Recursively remove the temporary directory. */ + (void) glnx_tmpdir_delete (&fixture->tmpdir, NULL, NULL); +} + +/* Test that the hash values for two #OstreeRepo instances pointing at the same + * repository are equal. We can’t test anything else, since hash collisions are + * always a possibility. */ +static void +test_repo_hash (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(OstreeRepo) repo1 = ostree_repo_create_at (fixture->tmpdir.fd, ".", + OSTREE_REPO_MODE_ARCHIVE, + NULL, + NULL, &error); + g_assert_no_error (error); + + g_autoptr(OstreeRepo) repo2 = ostree_repo_open_at (fixture->tmpdir.fd, ".", + NULL, &error); + g_assert_no_error (error); + + g_assert_cmpuint (ostree_repo_hash (repo1), ==, ostree_repo_hash (repo2)); +} + +/* Test that trying to hash a closed repo results in an assertion failure. */ +static void +test_repo_hash_closed (Fixture *fixture, + gconstpointer test_data) +{ + if (g_test_subprocess ()) + { + g_autoptr(GFile) repo_path = g_file_new_for_path (fixture->tmpdir.path); + g_autoptr(OstreeRepo) repo = ostree_repo_new (repo_path); + + ostree_repo_hash (repo); + + return; + } + + g_test_trap_subprocess (NULL, 0, 0); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*ERROR*ostree_repo_hash: assertion failed:*"); +} + +/* Test that various repositories test equal (or not) with each other. */ +static void +test_repo_equal (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr(GError) error = NULL; + + /* Create a few separate repos and some #OstreeRepo objects for them. */ + glnx_ensure_dir (fixture->tmpdir.fd, "repo1", 0755, &error); + g_assert_no_error (error); + glnx_ensure_dir (fixture->tmpdir.fd, "repo2", 0755, &error); + g_assert_no_error (error); + + g_autoptr(OstreeRepo) repo1 = ostree_repo_create_at (fixture->tmpdir.fd, "repo1", + OSTREE_REPO_MODE_ARCHIVE, + NULL, + NULL, &error); + g_assert_no_error (error); + + g_autoptr(OstreeRepo) repo1_alias = ostree_repo_open_at (fixture->tmpdir.fd, "repo1", + NULL, &error); + g_assert_no_error (error); + + g_autoptr(OstreeRepo) repo2 = ostree_repo_create_at (fixture->tmpdir.fd, "repo2", + OSTREE_REPO_MODE_ARCHIVE, + NULL, + NULL, &error); + g_assert_no_error (error); + + g_autoptr(GFile) closed_repo_path = g_file_new_for_path (fixture->tmpdir.path); + g_autoptr(OstreeRepo) closed_repo = ostree_repo_new (closed_repo_path); + + /* Test various equalities. */ + g_assert_true (ostree_repo_equal (repo1, repo1)); + g_assert_true (ostree_repo_equal (repo1_alias, repo1_alias)); + g_assert_true (ostree_repo_equal (repo1, repo1_alias)); + g_assert_true (ostree_repo_equal (repo1_alias, repo1)); + g_assert_true (ostree_repo_equal (repo2, repo2)); + g_assert_false (ostree_repo_equal (repo1, repo2)); + g_assert_false (ostree_repo_equal (repo1_alias, repo2)); + g_assert_false (ostree_repo_equal (repo2, repo1)); + g_assert_false (ostree_repo_equal (repo2, repo1_alias)); + g_assert_false (ostree_repo_equal (repo1, closed_repo)); + g_assert_false (ostree_repo_equal (repo1_alias, closed_repo)); + g_assert_false (ostree_repo_equal (closed_repo, repo1)); + g_assert_false (ostree_repo_equal (closed_repo, repo1_alias)); + g_assert_false (ostree_repo_equal (repo2, closed_repo)); + g_assert_false (ostree_repo_equal (closed_repo, repo2)); + g_assert_false (ostree_repo_equal (closed_repo, closed_repo)); +} + +static void +test_repo_get_min_free_space (Fixture *fixture, + gconstpointer test_data) +{ + g_autoptr (GKeyFile) config = NULL; + g_autoptr(GError) error = NULL; + guint64 bytes = 0; + typedef struct + { + const char *val; + gboolean should_succeed; + } min_free_space_value; + + g_autoptr(OstreeRepo) repo = ostree_repo_create_at (fixture->tmpdir.fd, ".", + OSTREE_REPO_MODE_ARCHIVE, + NULL, + NULL, &error); + g_assert_no_error (error); + + min_free_space_value values_to_test[] = { + {"500MB", TRUE }, + { "0MB", TRUE }, + { "17179869185GB", FALSE }, /* Overflow parameter: bytes > G_MAXUINT64 */ + { NULL, FALSE } + }; + + config = ostree_repo_copy_config (repo); + + for (guint i = 0; values_to_test[i].val != NULL; i++) + { + g_key_file_remove_key (config, "core", "min-free-space-size", NULL); + g_key_file_set_string (config, "core", "min-free-space-size", values_to_test[i].val); + + ostree_repo_write_config (repo, config, &error); + g_assert_no_error (error); + ostree_repo_reload_config (repo, NULL, &error); + g_assert_no_error (error); + + ostree_repo_get_min_free_space_bytes (repo, &bytes, &error); + if (values_to_test[i].should_succeed) + g_assert_no_error (error); + else + continue; + } +} + +int +main (int argc, + char **argv) +{ + setlocale (LC_ALL, ""); + g_test_init (&argc, &argv, NULL); + + g_test_add ("/repo/hash", Fixture, NULL, setup, + test_repo_hash, teardown); + g_test_add ("/repo/hash/closed", Fixture, NULL, setup, + test_repo_hash_closed, teardown); + g_test_add ("/repo/equal", Fixture, NULL, setup, + test_repo_equal, teardown); + g_test_add ("/repo/get_min_free_space", Fixture, NULL, setup, + test_repo_get_min_free_space, teardown); + + + return g_test_run (); +} diff --git a/tests/test-reset-nonlinear.sh b/tests/test-reset-nonlinear.sh new file mode 100755 index 0000000..dca1be9 --- /dev/null +++ b/tests/test-reset-nonlinear.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# +# Copyright (C) 2015 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +echo "1..1" + +. $(dirname $0)/libtest.sh + +setup_test_repository "archive" +cd ${test_tmpdir}/files +$OSTREE commit -b testx -s "Another Commit" +cd ${test_tmpdir} +$OSTREE reset test2 testx + +echo "ok reset nonlinear" diff --git a/tests/test-rofiles-fuse.sh b/tests/test-rofiles-fuse.sh new file mode 100755 index 0000000..1e09711 --- /dev/null +++ b/tests/test-rofiles-fuse.sh @@ -0,0 +1,176 @@ +#!/bin/bash +# +# Copyright (C) 2016 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip_without_fuse +skip_without_user_xattrs + +setup_test_repository "bare" + +echo "1..11" + +cd ${test_tmpdir} +mkdir mnt +# The default content set amazingly doesn't have a non-broken link +ln -s firstfile files/firstfile-link +$OSTREE commit -b test2 --tree=dir=files +$OSTREE checkout -H test2 checkout-test2 + +rofiles-fuse checkout-test2 mnt +cleanup_fuse() { + fusermount -u ${test_tmpdir}/mnt || true +} +libtest_exit_cmds+=(cleanup_fuse) +assert_file_has_content mnt/firstfile first +echo "ok mount" + +# Test open(O_TRUNC) directly and via symlink +for path in firstfile{,-link}; do + if cp /dev/null mnt/${path} 2>err.txt; then + assert_not_reached "inplace mutation ${path}" + fi + assert_file_has_content err.txt "Read-only file system" + assert_file_has_content mnt/firstfile first + assert_file_has_content checkout-test2/firstfile first +done +echo "ok failed inplace mutation (open O_TRUNCATE)" + +# Test chmod +if chmod 0600 mnt/firstfile 2>err.txt; then + assert_not_reached "chmod inplace" +fi +assert_file_has_content err.txt "chmod:.*Read-only file system" +# Test chown with regfiles and symlinks +for path in firstfile baz/alink; do + if chown -h $(id -u) mnt/${path} 2>err.txt; then + assert_not_reached "chown inplace ${path}" + fi + assert_file_has_content err.txt "chown:.*Read-only file system" +done +# And test via dereferencing a symlink +if chown $(id -u) mnt/firstfile-link 2>err.txt; then + assert_not_reached "chown inplace firstfile-link" +fi +assert_file_has_content err.txt "chown:.*Read-only file system" +echo "ok failed mutation chmod + chown" + +# Test creating new files, using chown + chmod on them as well +echo anewfile-for-fuse > mnt/anewfile-for-fuse +assert_file_has_content mnt/anewfile-for-fuse anewfile-for-fuse +assert_file_has_content checkout-test2/anewfile-for-fuse anewfile-for-fuse +ln -s anewfile-for-fuse mnt/anewfile-for-fuse-link +# And also test modifications through a symlink +echo writevialink > mnt/anewfile-for-fuse-link +for path in anewfile-for-fuse{,-link}; do + assert_file_has_content mnt/${path} writevialink +done +chown $(id -u) mnt/anewfile-for-fuse-link + +mkdir mnt/newfusedir +for i in $(seq 5); do + echo ${i}-morenewfuse-${i} > mnt/newfusedir/test-morenewfuse.${i} + chmod 0600 mnt/newfusedir/test-morenewfuse.${i} + chown $(id -u) mnt/newfusedir/test-morenewfuse.${i} +done +assert_file_has_content checkout-test2/newfusedir/test-morenewfuse.3 3-morenewfuse-3 +echo "ok new content" + +rm mnt/baz/cow +assert_not_has_file checkout-test2/baz/cow +rm mnt/baz/another -rf +assert_not_has_dir checkout-test2/baz/another + +echo "ok deletion" + +${CMD_PREFIX} ostree --repo=repo commit -b test2 -s fromfuse --link-checkout-speedup --tree=dir=checkout-test2 + +echo "ok commit" + +${CMD_PREFIX} ostree --repo=repo checkout -U test2 mnt/test2-checkout-copy-fallback +assert_file_has_content mnt/test2-checkout-copy-fallback/anewfile-for-fuse writevialink + +if ${CMD_PREFIX} ostree --repo=repo checkout -UH test2 mnt/test2-checkout-copy-hardlinked 2>err.txt; then + assert_not_reached "Checking out via hardlinks across mountpoint unexpectedly succeeded!" +fi +assert_file_has_content err.txt "Unable to do hardlink checkout across devices" + +echo "ok checkout copy fallback" + +# check that O_RDONLY|O_CREAT is handled correctly; used by flock(1) at least +flock mnt/nonexistent-file echo "ok create file in ro mode" +echo "ok flock" + +# And now with --copyup enabled + +copyup_reset() { + cd ${test_tmpdir} + fusermount -u mnt + rm checkout-test2 -rf + $OSTREE checkout -H test2 checkout-test2 + rofiles-fuse --copyup checkout-test2 mnt +} + +assert_test_file() { + t=$1 + f=$2 + if ! test ${t} "${f}"; then + ls -al "${f}" + fatal "Failed test ${t} ${f}" + fi +} + +copyup_reset +assert_file_has_content mnt/firstfile first +echo "ok copyup mount" + +# Test O_TRUNC directly +firstfile_orig_inode=$(stat -c %i checkout-test2/firstfile) +echo -n truncating > mnt/firstfile +assert_streq "$(cat mnt/firstfile)" truncating +firstfile_new_inode=$(stat -c %i checkout-test2/firstfile) +assert_not_streq "${firstfile_orig_inode}" "${firstfile_new_inode}" +assert_test_file -f checkout-test2/firstfile + +copyup_reset +firstfile_link_orig_inode=$(stat -c %i checkout-test2/firstfile-link) +firstfile_orig_inode=$(stat -c %i checkout-test2/firstfile) +# Now write via the symlink +echo -n truncating > mnt/firstfile-link +assert_streq "$(cat mnt/firstfile)" truncating +firstfile_new_inode=$(stat -c %i checkout-test2/firstfile) +firstfile_link_new_inode=$(stat -c %i checkout-test2/firstfile-link) +assert_not_streq "${firstfile_orig_inode}" "${firstfile_new_inode}" +assert_streq "${firstfile_link_orig_inode}" "${firstfile_link_new_inode}" +assert_test_file -f checkout-test2/firstfile +# Verify we didn't replace the link with a regfile somehow +assert_test_file -L checkout-test2/firstfile-link + +# These both end up creating new files; in the sed case we'll then do a rename() +copyup_reset +echo "hello new file" > mnt/a-new-non-copyup-file +assert_file_has_content_literal mnt/a-new-non-copyup-file "hello new file" +sed -i -e s,first,second, mnt/firstfile +assert_file_has_content_literal mnt/firstfile "second" + +echo "ok copyup" diff --git a/tests/test-rollsum-cli.c b/tests/test-rollsum-cli.c new file mode 100644 index 0000000..6e5f9f4 --- /dev/null +++ b/tests/test-rollsum-cli.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-rollsum.h" + +#include "libglnx.h" + +int +main (int argc, char **argv) +{ + g_autoptr(GError) local_error = NULL; + GError **error = &local_error; + GBytes *from_bytes = NULL; + GBytes *to_bytes = NULL; + const char *from_path; + const char *to_path; + OstreeRollsumMatches *matches; + GMappedFile *mfile; + + g_setenv ("GIO_USE_VFS", "local", TRUE); + + if (argc < 3) + return 1; + + from_path = argv[1]; + to_path = argv[2]; + + mfile = g_mapped_file_new (from_path, FALSE, error); + if (!mfile) + goto out; + from_bytes = g_mapped_file_get_bytes (mfile); + g_mapped_file_unref (mfile); + mfile = g_mapped_file_new (to_path, FALSE, error); + if (!mfile) + goto out; + to_bytes = g_mapped_file_get_bytes (mfile); + g_mapped_file_unref (mfile); + + matches = _ostree_compute_rollsum_matches (from_bytes, to_bytes); + + g_printerr ("rollsum crcs=%u bufs=%u total=%u matchsize=%llu\n", + matches->crcmatches, + matches->bufmatches, + matches->total, (unsigned long long)matches->match_size); + + out: + if (local_error) + { + g_printerr ("%s\n", local_error->message); + return 1; + } + return 0; +} diff --git a/tests/test-rollsum.c b/tests/test-rollsum.c new file mode 100644 index 0000000..08c78b6 --- /dev/null +++ b/tests/test-rollsum.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libglnx.h" +#include "bsdiff/bsdiff.h" +#include "bsdiff/bspatch.h" +#include +#include +#include +#include +#include "ostree-rollsum.h" +#include "bupsplit.h" + +static void +test_rollsum_helper (const unsigned char *a, gsize size_a, const unsigned char *b, gsize size_b, gboolean expected_match) +{ + gsize i; + g_autoptr(GBytes) bytes_a = g_bytes_new_static (a, size_a); + g_autoptr(GBytes) bytes_b = g_bytes_new_static (b, size_b); + OstreeRollsumMatches *matches; + GPtrArray *matchlist; + guint64 sum_matched = 0; + + matches = _ostree_compute_rollsum_matches (bytes_a, bytes_b); + matchlist = matches->matches; + if (expected_match) + g_assert_cmpint (matchlist->len, >, 0); + else + g_assert_cmpint (matchlist->len, ==, 0); + + for (i = 0; i < matchlist->len; i++) + { + guint32 crc; + GVariant *match = matchlist->pdata[i]; + guint64 offset = 0, to_start = 0, from_start = 0; + g_variant_get (match, "(uttt)", &crc, &offset, &to_start, &from_start); + + g_assert_cmpint (offset, >=, 0); + g_assert_cmpint (from_start, <, size_a); + g_assert_cmpint (to_start, <, size_b); + + sum_matched += offset; + + g_assert_cmpint (memcmp (a + from_start, b + to_start, offset), ==, 0); + } + + g_assert_cmpint (sum_matched, ==, matches->match_size); + + _ostree_rollsum_matches_free (matches); +} + +static void +test_rollsum (void) +{ +#define MAX_BUFFER_SIZE 1000000 + gsize i; + int len; + g_autofree unsigned char *a = malloc (MAX_BUFFER_SIZE); + g_autofree unsigned char *b = malloc (MAX_BUFFER_SIZE); + g_autoptr(GRand) rand = g_rand_new (); + + /* These two buffers produce the same crc32. */ + const unsigned char conflicting_a[] = {0x35, 0x9b, 0x94, 0x5a, 0xa0, 0x5a, 0x34, 0xdc, 0x5c, 0x3, 0x46, 0xe, 0x34, 0x53, 0x85, 0x73, 0x64, 0xcc, 0x47, 0x10, 0x23, 0x8e, 0x7e, 0x6a, 0xca, 0xda, 0x7c, 0x12, 0x8a, 0x59, 0x7f, 0x7f, 0x4d, 0x1, 0xd8, 0xcc, 0x81, 0xcf, 0x2c, 0x7f, 0x10, 0xc2, 0xb4, 0x40, 0x1f, 0x2a, 0x0, 0x37, 0x85, 0xde, 0xfe, 0xa5, 0xc, 0x7c, 0xa1, 0x8, 0xd6, 0x75, 0xfd, 0x2, 0xcf, 0x2d, 0x53, 0x1b, 0x8a, 0x6b, 0x35, 0xad, 0xa, 0x8f, 0xad, 0x2d, 0x91, 0x87, 0x2b, 0x97, 0xcf, 0x1d, 0x7c, 0x61, 0xc4, 0xb2, 0x5e, 0xc3, 0xba, 0x5d, 0x2f, 0x3a, 0xeb, 0x41, 0x61, 0x4c, 0xa2, 0x34, 0xd, 0x43, 0xce, 0x10, 0xa3, 0x47, 0x4, 0xa0, 0x39, 0x77, 0xc2, 0xe8, 0x36, 0x1d, 0x87, 0xd1, 0x8f, 0x4d, 0x13, 0xa1, 0x34, 0xc3, 0x2c, 0xee, 0x1a, 0x10, 0x79, 0xb7, 0x97, 0x29, 0xe8, 0xf0, 0x5, 0xfc, 0xe6, 0x14, 0x87, 0x9c, 0x8f, 0x97, 0x23, 0xac, 0x1, 0xf2, 0xee, 0x69, 0xb2, 0xe5}; + + const unsigned char conflicting_b[] = {0xb2, 0x54, 0x81, 0x7d, 0x31, 0x83, 0xc7, 0xc, 0xcf, 0x7d, 0x90, 0x1c, 0x6b, 0xf6, 0x4e, 0xff, 0x49, 0xd1, 0xb6, 0xc, 0x9e, 0x85, 0xe3, 0x2d, 0xdb, 0x94, 0x8e, 0x1a, 0x17, 0x3f, 0x63, 0x59, 0xf9, 0x4b, 0x5f, 0x47, 0x97, 0x9c, 0x1c, 0xd7, 0x24, 0xd9, 0x42, 0x6, 0x1e, 0xf, 0x98, 0x10, 0xb4, 0xc, 0x50, 0xcb, 0xc5, 0x62, 0x53, 0x1, 0xd1, 0x5f, 0x16, 0x97, 0xaa, 0xd7, 0x57, 0x5e, 0xf2, 0xde, 0xae, 0x53, 0x58, 0x6, 0xb7, 0x9b, 0x8d, 0x2b, 0xd6, 0xb4, 0x55, 0x29, 0x3b, 0x27, 0x70, 0xd5, 0xf3, 0x8d, 0xdc, 0xad, 0x68, 0x63, 0xa5, 0x72, 0xce, 0x6b, 0x9, 0x2b, 0x60, 0x1b, 0x99, 0xd7, 0x86}; + + test_rollsum_helper (conflicting_a, sizeof conflicting_a, conflicting_b, sizeof conflicting_b, FALSE); + + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + a[i] = g_rand_int (rand); + b[i] = a[i]; + } + test_rollsum_helper (a, MAX_BUFFER_SIZE, b, MAX_BUFFER_SIZE, TRUE); + + /* Do not overwrite the first buffer. */ + len = bupsplit_find_ofs (b, MAX_BUFFER_SIZE, NULL); + if (len) + { + unsigned char *ptr = b + len; + gsize remaining = MAX_BUFFER_SIZE - len; + while (remaining) + { + len = bupsplit_find_ofs (ptr, remaining, NULL); + if (len == 0) + break; + *ptr = ~(*ptr); + remaining -= len; + ptr += len; + } + } + test_rollsum_helper (a, MAX_BUFFER_SIZE, b, MAX_BUFFER_SIZE, TRUE); + + /* Duplicate the first buffer. */ + len = bupsplit_find_ofs (b, MAX_BUFFER_SIZE, NULL); + if (len && len < MAX_BUFFER_SIZE / 2) + { + memcpy (b + len, b, len); + } + test_rollsum_helper (a, MAX_BUFFER_SIZE, b, MAX_BUFFER_SIZE, TRUE); + + /* All different. */ + for (i = 0; i < MAX_BUFFER_SIZE; i++) + { + a[i] = g_rand_int (rand); + b[i] = a[i] + 1; + } + test_rollsum_helper (a, MAX_BUFFER_SIZE, b, MAX_BUFFER_SIZE, FALSE); + + /* All different. */ + a[0] = g_rand_int (rand); + b[0] = a[0] + 1; + for (i = 1; i < MAX_BUFFER_SIZE; i++) + { + a[i] = g_rand_int (rand); + b[i] = g_rand_int (rand); + } + test_rollsum_helper (a, MAX_BUFFER_SIZE, b, MAX_BUFFER_SIZE, FALSE); +} + +#define BUP_SELFTEST_SIZE 100000 + +static void +test_bupsplit_sum(void) +{ + g_autofree uint8_t *buf = g_malloc (BUP_SELFTEST_SIZE); + uint32_t sum1a, sum1b, sum2a, sum2b, sum3a, sum3b; + unsigned count; + + for (count = 0; count < BUP_SELFTEST_SIZE; count++) + buf[count] = g_random_int_range (0, 256); + + sum1a = bupsplit_sum(buf, 0, BUP_SELFTEST_SIZE); + sum1b = bupsplit_sum(buf, 1, BUP_SELFTEST_SIZE); + sum2a = bupsplit_sum(buf, BUP_SELFTEST_SIZE - BUP_WINDOWSIZE*5/2, + BUP_SELFTEST_SIZE - BUP_WINDOWSIZE); + sum2b = bupsplit_sum(buf, 0, BUP_SELFTEST_SIZE - BUP_WINDOWSIZE); + sum3a = bupsplit_sum(buf, 0, BUP_WINDOWSIZE+3); + sum3b = bupsplit_sum(buf, 3, BUP_WINDOWSIZE+3); + + g_assert_cmpint (sum1a, ==, sum1b); + g_assert_cmpint (sum2a, ==, sum2b); + g_assert_cmpint (sum3a, ==, sum3b); +} + +int main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_add_func ("/rollsum", test_rollsum); + g_test_add_func ("/bupsum", test_bupsplit_sum); + return g_test_run(); +} diff --git a/tests/test-signed-commit.sh b/tests/test-signed-commit.sh new file mode 100755 index 0000000..d43efef --- /dev/null +++ b/tests/test-signed-commit.sh @@ -0,0 +1,208 @@ +#!/bin/bash +# +# Copyright (C) 2019 Collabora Ltd. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..11" + +# This is explicitly opt in for testing +export OSTREE_DUMMY_SIGN_ENABLED=1 + +mkdir ${test_tmpdir}/repo +ostree_repo_init repo --mode="archive" + +echo "Unsigned commit" > file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit' +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" + +# Test `ostree sign` with dummy module first +DUMMYSIGN="dummysign" +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy ${COMMIT} ${DUMMYSIGN} + +# Ensure that detached metadata really contain expected string +EXPECTEDSIGN="$(echo $DUMMYSIGN | hexdump -n 9 -e '8/1 "0x%.2x, " 1/1 " 0x%.2x"')" +${CMD_PREFIX} ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.dummy | grep -q -e "${EXPECTEDSIGN}" +echo "ok Detached dummy signature added" + +# Verify vith sign mechanism +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} +echo "ok dummy signature verified" + +echo "Signed commit with dummy key: ${DUMMYSIGN}" >> file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Signed with dummy module' --sign=${DUMMYSIGN} --sign-type=dummy +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} +echo "ok commit with dummy signing" + +if ${CMD_PREFIX} env -u OSTREE_DUMMY_SIGN_ENABLED ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} 2>err.txt; then + fatal "verified dummy signature without env" +fi +# FIXME the error message here is broken +#assert_file_has_content_literal err.txt 'dummy signature type is only for ostree testing' +assert_file_has_content_literal err.txt ' No valid signatures found' +echo "ok dummy sig requires env" + +# tests below require libsodium support +if ! has_sign_ed25519; then + echo "ok Detached ed25519 signature # SKIP due libsodium unavailability" + echo "ok ed25519 signature verified # SKIP due libsodium unavailability" + echo "ok multiple signing # SKIP due libsodium unavailability" + echo "ok verify ed25519 keys file # SKIP due libsodium unavailability" + echo "ok sign with ed25519 keys file # SKIP due libsodium unavailability" + echo "ok verify ed25519 system-wide configuration # SKIP due libsodium unavailability" + echo "ok verify ed25519 revoking keys mechanism # SKIP due libsodium unavailability" + exit 0 +fi + +# Test ostree sign with 'ed25519' module +gen_ed25519_keys +PUBLIC=${ED25519PUBLIC} +SEED=${ED25519SEED} +SECRET=${ED25519SECRET} + +WRONG_PUBLIC="$(gen_ed25519_random_public)" + +echo "SEED = $SEED" +echo "PUBLIC = $PUBLIC" + +echo "Signed commit with ed25519: ${SECRET}" >> file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s "Signed with ed25519 module" --sign="${SECRET}" --sign-type=ed25519 +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" + +# Ensure that detached metadata contain signature +${CMD_PREFIX} ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.ed25519 &>/dev/null +echo "ok Detached ed25519 signature added" + +# Verify vith sign mechanism +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${WRONG_PUBLIC}; then + exit 1 +fi +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${PUBLIC} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${PUBLIC} ${PUBLIC} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} $(gen_ed25519_random_public) ${PUBLIC} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} $(gen_ed25519_random_public) $(gen_ed25519_random_public) ${PUBLIC} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${PUBLIC} $(gen_ed25519_random_public) $(gen_ed25519_random_public) +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} $(gen_ed25519_random_public) $(gen_ed25519_random_public) ${PUBLIC} $(gen_ed25519_random_public) $(gen_ed25519_random_public) +echo "ok ed25519 signature verified" + +# Check if we able to use all available modules to sign the same commit +echo "Unsigned commit for multi-sign" >> file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit' +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" +# Check if we have no signatures +for mod in "dummy" "ed25519"; do + if ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.${mod}; then + echo "Unexpected signature for ${mod} found" + exit 1 + fi +done + +# Sign with all available modules +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy ${COMMIT} ${DUMMYSIGN} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=ed25519 ${COMMIT} ${SECRET} +# and verify +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 ${COMMIT} ${PUBLIC} >out.txt +assert_file_has_content out.txt "ed25519: Signature verified successfully with key" +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} >out.txt +assert_file_has_content out.txt "dummy: Signature verified" +echo "ok multiple signing " + +# Prepare files with public ed25519 signatures +PUBKEYS="$(mktemp -p ${test_tmpdir} ed25519_XXXXXX.ed25519)" + +# Test if file contain no keys +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT}; then + exit 1 +fi + +# Test if have a problem with file object +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${test_tmpdir} ${COMMIT}; then + exit 1 +fi + +# Test with single key in list +echo ${PUBLIC} > ${PUBKEYS} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} >out.txt +assert_file_has_content out.txt 'ed25519: Signature verified successfully' + +# Test the file with multiple keys without a valid public key +for((i=0;i<100;i++)); do + # Generate a list with some public signatures + gen_ed25519_random_public +done > ${PUBKEYS} +# Check if file contain no valid signatures +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} 2>err.txt; then + fatal "validated with no signatures" +fi +assert_file_has_content err.txt 'error:.* ed25519: Signature couldn.t be verified; tried 100 keys' +# Check if no valid signatures provided via args&file +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} ${WRONG_PUBLIC}; then + exit 1 +fi + +#Test keys file and public key +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} ${PUBLIC} + +# Add correct key into the list +echo ${PUBLIC} >> ${PUBKEYS} +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} + +echo "ok verify ed25519 keys file" + +# Check ed25519 signing with secret file +echo "Unsigned commit for secret file usage" >> file.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit' +COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)" + +KEYFILE="$(mktemp -p ${test_tmpdir} secret_XXXXXX.ed25519)" +echo "${SECRET}" > ${KEYFILE} +# Sign +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=ed25519 --keys-file=${KEYFILE} ${COMMIT} +# Verify +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-file=${PUBKEYS} ${COMMIT} +echo "ok sign with ed25519 keys file" + +# Check the well-known places mechanism +mkdir -p ${test_tmpdir}/{trusted,revoked}.ed25519.d +for((i=0;i<100;i++)); do + # Generate some key files with random public signatures + gen_ed25519_random_public > ${test_tmpdir}/trusted.ed25519.d/signature_$i +done +# Check no valid public keys are available +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-dir=${test_tmpdir} ${COMMIT}; then + exit 1 +fi +echo ${PUBLIC} > ${test_tmpdir}/trusted.ed25519.d/correct +# Verify with correct key +${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-dir=${test_tmpdir} ${COMMIT} + +echo "ok verify ed25519 system-wide configuration" + +# Add the public key into revoked list +echo ${PUBLIC} > ${test_tmpdir}/revoked.ed25519.d/correct +# Check if public key is not valid anymore +if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=ed25519 --keys-dir=${test_tmpdir} ${COMMIT}; then + exit 1 +fi +rm -rf ${test_tmpdir}/{trusted,revoked}.ed25519.d +echo "ok verify ed25519 revoking keys mechanism" diff --git a/tests/test-signed-pull-summary.sh b/tests/test-signed-pull-summary.sh new file mode 100755 index 0000000..e953f2e --- /dev/null +++ b/tests/test-signed-pull-summary.sh @@ -0,0 +1,290 @@ +#!/bin/bash +# +# Copyright (C) 2019 Collabora Ltd. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# Based on test-pull-summary-sigs.sh test. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..14" + +# This is explicitly opt in for testing +export OSTREE_DUMMY_SIGN_ENABLED=1 + +repo_reinit () { + ARGS="$*" + cd ${test_tmpdir} + rm -rf repo + mkdir repo + ostree_repo_init repo --mode=archive + ${OSTREE} --repo=repo remote add \ + --set=gpg-verify=false --set=gpg-verify-summary=false \ + --set=sign-verify=false --set=sign-verify-summary=true \ + ${ARGS} origin $(cat httpd-address)/ostree/gnomerepo +} + +for engine in dummy ed25519 +do + case "${engine}" in + dummy) + # Tests with dummy engine + SIGN_KEY="dummysign" + PUBLIC_KEY="dummysign" + ;; + ed25519) + if ! has_sign_ed25519; then + echo "ok ${engine} pull mirror summary # SKIP due libsodium unavailability" + echo "ok ${engine} pull with signed summary # SKIP due libsodium unavailability" + echo "ok ${engine} prune summary cache # SKIP due libsodium unavailability" + echo "ok ${engine} pull with signed summary and cachedir # SKIP due libsodium unavailability" + echo "ok ${engine} pull with invalid ${engine} summary signature fails # SKIP due libsodium unavailability" + echo "ok ${engine} pull delta with signed summary # SKIP due libsodium unavailability" + + continue + fi + gen_ed25519_keys + SIGN_KEY="${ED25519SECRET}" + PUBLIC_KEY="${ED25519PUBLIC}" + ;; + *) + fatal "Unsupported engine ${engine}" + ;; + esac + + COMMIT_SIGN="--sign-type=${engine} --sign=${SIGN_KEY}" + + # clenup the testdir prior the next engine + rm -rf ${test_tmpdir}/ostree-srv ${test_tmpdir}/gnomerepo ${test_tmpdir}/httpd ${test_tmpdir}/repo ${test_tmpdir}/cachedir\ + ${test_tmpdir}/main-copy ${test_tmpdir}/other-copy ${test_tmpdir}/yet-another-copy + + setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" + + # Now, setup multiple branches + mkdir ${test_tmpdir}/ostree-srv/other-files + cd ${test_tmpdir}/ostree-srv/other-files + echo 'hello world another object' > hello-world + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b other -s "A commit" -m "Another Commit body" + + mkdir ${test_tmpdir}/ostree-srv/yet-other-files + cd ${test_tmpdir}/ostree-srv/yet-other-files + echo 'hello world yet another object' > yet-another-hello-world + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b yet-another -s "A commit" -m "Another Commit body" + + ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u + + prev_dir=`pwd` + cd ${test_tmpdir} + ostree_repo_init repo --mode=archive + ${CMD_PREFIX} ostree --repo=repo remote add \ + --set=gpg-verify=false --set=gpg-verify-summary=false \ + --set=sign-verify=false --set=sign-verify-summary=false \ + origin $(cat httpd-address)/ostree/gnomerepo + ${CMD_PREFIX} ostree --repo=repo pull --mirror origin + assert_has_file repo/summary + ${CMD_PREFIX} ostree --repo=repo checkout -U main main-copy + assert_file_has_content main-copy/baz/cow "moo" + ${CMD_PREFIX} ostree --repo=repo checkout -U other other-copy + assert_file_has_content other-copy/hello-world "hello world another object" + ${CMD_PREFIX} ostree --repo=repo checkout -U yet-another yet-another-copy + assert_file_has_content yet-another-copy/yet-another-hello-world "hello world yet another object" + ${CMD_PREFIX} ostree --repo=repo fsck + echo "ok ${engine} pull mirror summary" + + + cd $prev_dir + + ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} + + cd ${test_tmpdir} + repo_reinit --set=verification-${engine}-key=${PUBLIC_KEY} + ${OSTREE} --repo=repo pull origin main + assert_has_file repo/tmp/cache/summaries/origin + assert_has_file repo/tmp/cache/summaries/origin.sig + + rm repo/tmp/cache/summaries/origin + ${OSTREE} --repo=repo pull origin main + assert_has_file repo/tmp/cache/summaries/origin + + echo "ok ${engine} pull with signed summary" + + touch repo/tmp/cache/summaries/foo + touch repo/tmp/cache/summaries/foo.sig + ${OSTREE} --repo=repo prune + assert_not_has_file repo/tmp/cache/summaries/foo + assert_not_has_file repo/tmp/cache/summaries/foo.sig + assert_has_file repo/tmp/cache/summaries/origin + assert_has_file repo/tmp/cache/summaries/origin.sig + echo "ok ${engine} prune summary cache" + + cd ${test_tmpdir} + repo_reinit --set=verification-${engine}-key=${PUBLIC_KEY} + mkdir cachedir + ${OSTREE} --repo=repo pull --cache-dir=cachedir origin main + assert_not_has_file repo/tmp/cache/summaries/origin + assert_not_has_file repo/tmp/cache/summaries/origin.sig + assert_has_file cachedir/summaries/origin + assert_has_file cachedir/summaries/origin.sig + + rm cachedir/summaries/origin + ${OSTREE} --repo=repo pull --cache-dir=cachedir origin main + assert_not_has_file repo/tmp/cache/summaries/origin + assert_has_file cachedir/summaries/origin + + echo "ok ${engine} pull with signed summary and cachedir" + + cd ${test_tmpdir} + repo_reinit --set=verification-${engine}-key=${PUBLIC_KEY} + mv ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.good} + echo invalid > ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig + if ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Successful pull with invalid ${engine} signature" + fi + assert_file_has_content err.txt "No signatures found" + mv ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.good,} + echo "ok ${engine} pull with invalid ${engine} summary signature fails" + + # Generate a delta + ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo static-delta generate --empty main + ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} + + cd ${test_tmpdir} + repo_reinit --set=verification-${engine}-key=${PUBLIC_KEY} + ${OSTREE} --repo=repo pull origin main + echo "ok ${engine} pull delta with signed summary" + +done + +if ! has_sign_ed25519; then + echo "ok ${engine} pull with signed summary remote old summary # SKIP due libsodium unavailability" + echo "ok ${engine} pull with signed summary broken cache # SKIP due libsodium unavailability" + exit 0 +fi + +gen_ed25519_keys +SIGN_KEY="${ED25519SECRET}" +PUBLIC_KEY="${ED25519PUBLIC}" +COMMIT_SIGN="--sign-type=${engine} --sign=${SIGN_KEY}" + + +# Verify 'ostree remote summary' output. +${OSTREE} --repo=repo remote summary origin > summary.txt +assert_file_has_content summary.txt "* main" +assert_file_has_content summary.txt "* other" +assert_file_has_content summary.txt "* yet-another" +grep static-deltas summary.txt > static-deltas.txt +assert_file_has_content static-deltas.txt \ + $(${OSTREE} --repo=repo rev-parse origin:main) + +## Tests for handling of cached summaries while racing with remote summary updates + +# Make 2 different but valid summary/signature pairs to test races with +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{,.1} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.1} +mkdir ${test_tmpdir}/ostree-srv/even-another-files +cd ${test_tmpdir}/ostree-srv/even-another-files +echo 'hello world even another object' > even-another-hello-world +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b even-another -s "A commit" -m "Another Commit body" +${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{,.2} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{,.2} +cd ${test_tmpdir} + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit --set=verification-ed25519-key=${PUBLIC_KEY} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a pull race where the client gets the old summary and the new +# summary signature since it was generated on the server between the +# requests +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +if ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Successful pull with old summary" +fi +assert_file_has_content err.txt "ed25519: Signature couldn't be verified with: key" +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish correct summary and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok ${engine} pull with signed summary remote old summary" + + +# Reset to the old valid summary and pull to cache it +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.1,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.1,} +repo_reinit --set=verification-ed25519-key=${PUBLIC_KEY} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Simulate a broken summary cache to see if it can be recovered from. +# Prior to commit c4c2b5eb the client would save the summary to the +# cache before validating the signature. That would mean the cache would +# have mismatched summary and signature and ostree would remain +# deadlocked there until the remote published a new signature. +# +# First pull with OSTREE_REPO_TEST_ERROR=invalid-cache to see the +# invalid cache is detected. Then pull again to check if it can be +# recovered from. +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 repo/tmp/cache/summaries/origin +if OSTREE_REPO_TEST_ERROR=invalid-cache ${OSTREE} --repo=repo pull origin main 2>err.txt; then + assert_not_reached "Should have hit OSTREE_REPO_TEST_ERROR_INVALID_CACHE" +fi +assert_file_has_content err.txt "OSTREE_REPO_TEST_ERROR_INVALID_CACHE" +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.1 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.1 >&2 + +# Publish new signature and check that subsequent pull succeeds +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary{.2,} +cp ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig{.2,} +${OSTREE} --repo=repo pull origin main +assert_has_file repo/tmp/cache/summaries/origin +assert_has_file repo/tmp/cache/summaries/origin.sig +cmp repo/tmp/cache/summaries/origin ${test_tmpdir}/ostree-srv/gnomerepo/summary.2 >&2 +cmp repo/tmp/cache/summaries/origin.sig ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig.2 >&2 + +echo "ok ${engine} pull with signed summary broken cache" + diff --git a/tests/test-signed-pull.sh b/tests/test-signed-pull.sh new file mode 100755 index 0000000..fe78321 --- /dev/null +++ b/tests/test-signed-pull.sh @@ -0,0 +1,190 @@ +#!/bin/bash +# +# Copyright (C) 2019 Collabora Ltd. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..20" + +# This is explicitly opt in for testing +export OSTREE_DUMMY_SIGN_ENABLED=1 +setup_fake_remote_repo1 "archive" + +repo_mode="archive" + +function repo_init() { + cd ${test_tmpdir} + rm repo -rf + mkdir repo + ostree_repo_init repo --mode=${repo_mode} + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false --set=sign-verify-summary=false origin $(cat httpd-address)/ostree/gnomerepo "$@" +} + +function test_signed_pull() { + local sign_type="$1" + local comment="$2" + cd ${test_tmpdir} + ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} \ + -b main -s "A signed commit" --tree=ref=main + + ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + # make sure gpg verification is correctly on + csum=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo rev-parse main) + objpath=objects/${csum::2}/${csum:2}.commitmeta + remotesig=ostree-srv/gnomerepo/$objpath + localsig=repo/$objpath + mv $remotesig $remotesig.bak + if ${CMD_PREFIX} ostree --repo=repo --depth=0 pull origin main; then + assert_not_reached "pull with sign-verify and no commitmeta unexpectedly succeeded?" + fi + # ok now check that we can pull correctly + mv $remotesig.bak $remotesig + ${CMD_PREFIX} ostree --repo=repo pull origin main + echo "ok ${sign_type}${comment} pull signed commit" + rm $localsig + ${CMD_PREFIX} ostree --repo=repo pull origin main + test -f $localsig + echo "ok ${sign_type}${comment} re-pull signature for stored commit" +} + +DUMMYSIGN="dummysign" +COMMIT_ARGS="--sign=${DUMMYSIGN} --sign-type=dummy" +repo_init --set=sign-verify=true + +# Check if verification-key and verification-file options throw error with wrong keys +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit ${COMMIT_ARGS} \ + -b main -s "A signed commit" --tree=ref=main +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +if ${CMD_PREFIX} ostree --repo=repo pull origin main; then + assert_not_reached "pull without keys unexpectedly succeeded" +fi +echo "ok pull failure without keys preloaded" + +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-key "somewrongkey" +if ${CMD_PREFIX} ostree --repo=repo pull origin main; then + assert_not_reached "pull with unknown key unexpectedly succeeded" +fi +echo "ok pull failure with incorrect key option" + +${CMD_PREFIX} ostree --repo=repo config unset 'remote "origin"'.verification-dummy-key +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-file "/non/existing/file" +if ${CMD_PREFIX} ostree --repo=repo pull origin main; then + assert_not_reached "pull with unknown keys file unexpectedly succeeded" +fi +echo "ok pull failure with incorrect keys file option" + +# Test with correct dummy key +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-key "${DUMMYSIGN}" +${CMD_PREFIX} ostree --repo=repo config unset 'remote "origin"'.verification-dummy-file +test_signed_pull "dummy" "" + +# Another test with the --verify option directly +repo_init --sign-verify=dummy=inline:${DUMMYSIGN} +test_signed_pull "dummy" "from remote opt" + +# And now explicitly limit it to dummy +repo_init +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.sign-verify dummy +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-key "${DUMMYSIGN}" +test_signed_pull "dummy" "explicit value" + +# dummy, but no key configured +repo_init +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.sign-verify dummy +if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>err.txt; then + assert_not_reached "pull with nosuchsystem succeeded" +fi +assert_file_has_content err.txt 'No keys found for required signapi type dummy' +echo "ok explicit dummy but unconfigured" + +# Set it to an unknown explicit value +repo_init +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.sign-verify nosuchsystem; +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-dummy-key "${DUMMYSIGN}" +if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>err.txt; then + assert_not_reached "pull with nosuchsystem succeeded" +fi +assert_file_has_content err.txt 'Requested signature type is not implemented' +echo "ok pull failure for unknown system" + +repo_init +if ${CMD_PREFIX} ostree --repo=repo remote add other --sign-verify=trustme=inline:ok http://localhost 2>err.txt; then + assert_not_reached "remote add with invalid keytype succeeded" +fi +assert_file_has_content err.txt 'Requested signature type is not implemented' +if ${CMD_PREFIX} ostree --repo=repo remote add other --sign-verify=dummy http://localhost 2>err.txt; then + assert_not_reached "remote add with invalid keytype succeeded" +fi +assert_file_has_content err.txt 'Failed to parse KEYTYPE' +if ${CMD_PREFIX} ostree --repo=repo remote add other --sign-verify=dummy=foo:bar http://localhost 2>err.txt; then + assert_not_reached "remote add with invalid keytype succeeded" +fi +assert_file_has_content err.txt 'Invalid key reference' +echo "ok remote add errs" + +if ! has_sign_ed25519; then + echo "ok ed25519-key pull signed commit # SKIP due libsodium unavailability" + echo "ok ed25519-key re-pull signature for stored commit # SKIP due libsodium unavailability" + echo "ok ed25519-key+file pull signed commit # SKIP due libsodium unavailability" + echo "ok ed25519-key+file re-pull signature for stored commit # SKIP due libsodium unavailability" + echo "ok ed25519-file pull signed commit # SKIP due libsodium unavailability" + echo "ok ed25519-file re-pull signature for stored commit # SKIP due libsodium unavailability" + echo "ok ed25519-inline # SKIP due libsodium unavailability" + echo "ok ed25519-inline # SKIP due libsodium unavailability" + exit 0 +fi + +# Test ostree sign with 'ed25519' module +gen_ed25519_keys +PUBLIC=${ED25519PUBLIC} +SEED=${ED25519SEED} +SECRET=${ED25519SECRET} + +COMMIT_ARGS="--sign=${SECRET} --sign-type=ed25519" + +repo_init --set=sign-verify=true +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-ed25519-key "${PUBLIC}" +test_signed_pull "ed25519" "key" + +# Prepare files with public ed25519 signatures +PUBKEYS="$(mktemp -p ${test_tmpdir} ed25519_XXXXXX.ed25519)" + +# Test the file with multiple keys without a valid public key +for((i=0;i<100;i++)); do + # Generate a list with some public signatures + gen_ed25519_random_public +done > ${PUBKEYS} + +# Test case with the file containing incorrect signatures and with the correct key set +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-ed25519-file "${PUBKEYS}" +test_signed_pull "ed25519" "key+file" + +# Add correct key into the list +echo ${PUBLIC} >> ${PUBKEYS} + +repo_init --set=sign-verify=true +${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-ed25519-file "${PUBKEYS}" +test_signed_pull "ed25519" "file" + +repo_init --sign-verify=ed25519=inline:"${ED25519PUBLIC}" +test_signed_pull "ed25519" "--verify-ed25519" diff --git a/tests/test-sizes.js b/tests/test-sizes.js new file mode 100755 index 0000000..a224653 --- /dev/null +++ b/tests/test-sizes.js @@ -0,0 +1,217 @@ +#!/usr/bin/env gjs +// +// Copyright (C) 2013 Colin Walters +// +// SPDX-License-Identifier: LGPL-2.0+ +// +// 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 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., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; +const OSTree = imports.gi.OSTree; + +function assertEquals(a, b) { + if (a != b) + throw new Error("assertion failed " + JSON.stringify(a) + " == " + JSON.stringify(b)); +} + +function assertGreater(a, b) { + if (a <= b) + throw new Error("assertion failed " + JSON.stringify(a) + " > " + JSON.stringify(b)); +} + +function assertGreaterEquals(a, b) { + if (a < b) + throw new Error("assertion failed " + JSON.stringify(a) + " >= " + JSON.stringify(b)); +} + +// Adapted from _ostree_read_varuint64() +function readVarint(buffer) { + let result = 0; + let count = 0; + let len = buffer.length; + let cur; + + do { + assertGreater(len, 0); + cur = buffer[count]; + result = result | ((cur & 0x7F) << (7 * count)); + count++; + len--; + } while (cur & 0x80); + + return [result, count]; +} + +// There have been various bugs with byte array unpacking in GJS, so +// just do it manually. +function unpackByteArray(variant) { + let array = []; + let nBytes = variant.n_children(); + for (let i = 0; i < nBytes; i++) { + array.push(variant.get_child_value(i).get_byte()); + } + return array; +} + +function validateSizes(repo, commit, expectedObjects) { + let [,commitVariant] = repo.load_variant(OSTree.ObjectType.COMMIT, commit); + let metadata = commitVariant.get_child_value(0); + let sizes = metadata.lookup_value('ostree.sizes', GLib.VariantType.new('aay')); + let nObjects = sizes.n_children(); + let expectedNObjects = Object.keys(expectedObjects).length + assertEquals(nObjects, expectedNObjects); + + for (let i = 0; i < nObjects; i++) { + let sizeEntry = sizes.get_child_value(i); + assertGreaterEquals(sizeEntry.n_children(), 34); + let entryBytes = unpackByteArray(sizeEntry); + let checksumBytes = entryBytes.slice(0, 32); + let checksumString = OSTree.checksum_from_bytes(checksumBytes); + print("checksum = " + checksumString); + + // Read the sizes from the next 2 varints + let remainingBytes = entryBytes.slice(32); + assertGreaterEquals(remainingBytes.length, 2); + let varintRead; + let compressedSize; + let uncompressedSize; + [compressedSize, varintRead] = readVarint(remainingBytes); + remainingBytes = remainingBytes.slice(varintRead); + assertGreaterEquals(remainingBytes.length, 1); + [uncompressedSize, varintRead] = readVarint(remainingBytes); + remainingBytes = remainingBytes.slice(varintRead); + assertEquals(remainingBytes.length, 1); + let objectType = remainingBytes[0]; + let objectTypeString = OSTree.object_type_to_string(objectType); + print("compressed = " + compressedSize); + print("uncompressed = " + uncompressedSize); + print("objtype = " + objectTypeString + " (" + objectType + ")"); + let objectName = OSTree.object_to_string(checksumString, objectType); + print("object = " + objectName); + + if (!(objectName in expectedObjects)) { + throw new Error("Object " + objectName + " not in " + + JSON.stringify(expectedObjects)); + } + let expectedSizes = expectedObjects[objectName]; + let expectedCompressedSize = expectedSizes[0]; + let expectedUncompressedSize = expectedSizes[1]; + if (compressedSize != expectedCompressedSize) { + throw new Error("Compressed size " + compressedSize + + " for checksum " + checksumString + + " does not match expected " + expectedCompressedSize); + } + if (uncompressedSize != expectedUncompressedSize) { + throw new Error("Uncompressed size " + uncompressedSize + + " for checksum " + checksumString + + " does not match expected " + expectedUncompressedSize); + } + } +} + +print('1..3') + +let testDataDir = Gio.File.new_for_path('test-data'); +testDataDir.make_directory(null); +testDataDir.get_child('some-file').replace_contents("hello world!", null, false, 0, null); +testDataDir.get_child('some-file').copy(testDataDir.get_child('duplicate-file'), + Gio.FileCopyFlags.OVERWRITE, + null, null); +testDataDir.get_child('link-file').make_symbolic_link('some-file', null); +testDataDir.get_child('another-file').replace_contents("hello world again!", null, false, 0, null); + +let repoPath = Gio.File.new_for_path('repo'); +let repo = OSTree.Repo.new(repoPath); +repo.create(OSTree.RepoMode.ARCHIVE_Z2, null); + +repo.open(null); + +let commitModifierFlags = (OSTree.RepoCommitModifierFlags.GENERATE_SIZES | + OSTree.RepoCommitModifierFlags.SKIP_XATTRS | + OSTree.RepoCommitModifierFlags.CANONICAL_PERMISSIONS); +let commitModifier = OSTree.RepoCommitModifier.new(commitModifierFlags, null); + +assertEquals(repo.get_mode(), OSTree.RepoMode.ARCHIVE_Z2); + +repo.prepare_transaction(null); + +let mtree = OSTree.MutableTree.new(); +repo.write_directory_to_mtree(testDataDir, mtree, commitModifier, null); +let [,dirTree] = repo.write_mtree(mtree, null); +let [,commit] = repo.write_commit(null, 'Some subject', 'Some body', null, dirTree, null); +print("commit => " + commit); + +repo.commit_transaction(null); + +// Test the sizes metadata. The key is the object and the value is an +// array of compressed size and uncompressed size. +let expectedObjects = { + 'f5ee222a21e2c96edbd6f2543c4bc8a039f827be3823d04777c9ee187778f1ad.file': [ + 54, 18 + ], + 'd35bfc50864fca777dbeead3ba3689115b76674a093210316589b1fe5cc3ff4b.file': [ + 48, 12 + ], + '8322876a078e79d8c960b8b4658fe77e7b2f878f8a6cf89dbb87c6becc8128a0.file': [ + 43, 9 + ], + '1c77033ca06eae77ed99cb26472969964314ffd5b4e4c0fd3ff6ec4265c86e51.dirtree': [ + 185, 185 + ], + '446a0ef11b7cc167f3b603e585c7eeeeb675faa412d5ec73f62988eb0b6c5488.dirmeta': [ + 12, 12 + ], +}; +validateSizes(repo, commit, expectedObjects); + +print("ok test-sizes"); + +// Remove a file to make sure that metadata is not reused from the +// previous commit. Remove that file from the expected metadata and +// replace the dirtree object. +testDataDir.get_child('another-file').delete(null); +delete expectedObjects['f5ee222a21e2c96edbd6f2543c4bc8a039f827be3823d04777c9ee187778f1ad.file']; +delete expectedObjects['1c77033ca06eae77ed99cb26472969964314ffd5b4e4c0fd3ff6ec4265c86e51.dirtree']; +expectedObjects['a384660cc18ffdb60296961dde9a2d6f78f4fec095165652cb53aa81f6dc7539.dirtree'] = [ + 138, 138 +]; + +repo.prepare_transaction(null); +mtree = OSTree.MutableTree.new(); +repo.write_directory_to_mtree(testDataDir, mtree, commitModifier, null); +[,dirTree] = repo.write_mtree(mtree, null); +[,commit] = repo.write_commit(null, 'Some subject', 'Some body', null, dirTree, null); +print("commit => " + commit); +repo.commit_transaction(null); + +validateSizes(repo, commit, expectedObjects); + +print("ok test-sizes file deleted"); + +// Repeat the commit now that all the objects are cached and ensure the +// metadata is still correct +repo.prepare_transaction(null); +mtree = OSTree.MutableTree.new(); +repo.write_directory_to_mtree(testDataDir, mtree, commitModifier, null); +[,dirTree] = repo.write_mtree(mtree, null); +[,commit] = repo.write_commit(null, 'Another subject', 'Another body', null, dirTree, null); +print("commit => " + commit); +repo.commit_transaction(null); + +validateSizes(repo, commit, expectedObjects); + +print("ok test-sizes repeated"); diff --git a/tests/test-summary-collections.sh b/tests/test-summary-collections.sh new file mode 100755 index 0000000..9885c5e --- /dev/null +++ b/tests/test-summary-collections.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# +# Copyright © 2016 Red Hat, Inc. +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..1' + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo --collection-id org.example.Collection + +mkdir -p tree/root +touch tree/root/a + +# Add a few commits +seq 5 | while read i; do + echo a >> tree/root/a + ${CMD_PREFIX} ostree --repo=repo commit --branch=test-$i -m test -s test tree +done + +# Check that they are all listed, with the repository’s collection ID, in the summary. +${CMD_PREFIX} ostree --repo=repo summary --update + +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_file_has_content summary "(org\.example\.Collection, test-1)$" +assert_file_has_content summary "(org\.example\.Collection, test-2)$" +assert_file_has_content summary "(org\.example\.Collection, test-3)$" +assert_file_has_content summary "(org\.example\.Collection, test-4)$" +assert_file_has_content summary "(org\.example\.Collection, test-5)$" +assert_file_has_content summary "^Collection ID (ostree\.summary\.collection-id): org\.example\.Collection$" + +# Test that mirrored branches are listed too. +${CMD_PREFIX} ostree --repo=repo refs --collections --create=org.example.OtherCollection:test-1-mirror test-1 +${CMD_PREFIX} ostree --repo=repo summary --update + +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_file_has_content summary "(org\.example\.OtherCollection, test-1-mirror)$" + +# Test that remote refs are listed, but only if they have collection IDs +cd ${test_tmpdir} +mkdir collection-repo +ostree_repo_init collection-repo --collection-id org.example.RemoteCollection +mkdir -p adir +${CMD_PREFIX} ostree --repo=collection-repo commit --branch=rcommit -m rcommit -s rcommit adir +${CMD_PREFIX} ostree --repo=repo remote add --no-sign-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" +${CMD_PREFIX} ostree --repo=repo pull collection-repo-remote rcommit +${CMD_PREFIX} ostree --repo=repo summary --update + +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_file_has_content summary "(org\.example\.RemoteCollection, rcommit)$" + +cd ${test_tmpdir} +mkdir no-collection-repo +ostree_repo_init no-collection-repo +mkdir -p adir2 +${CMD_PREFIX} ostree --repo=no-collection-repo commit --branch=rcommit2 -m rcommit2 -s rcommit2 adir2 +${CMD_PREFIX} ostree --repo=repo remote add --no-sign-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" +${CMD_PREFIX} ostree --repo=repo pull no-collection-repo-remote rcommit2 +${CMD_PREFIX} ostree --repo=repo summary --update + +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_not_file_has_content summary "rcommit2" + +echo "ok summary collections" diff --git a/tests/test-summary-update.sh b/tests/test-summary-update.sh new file mode 100755 index 0000000..ceaa540 --- /dev/null +++ b/tests/test-summary-update.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Authors: +# - Philip Withnall + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..2" + +COMMIT_SIGN="" +if has_gpgme; then + COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" +fi + + +cd ${test_tmpdir} +mkdir repo +ostree_repo_init repo + +mkdir -p tree/root +touch tree/root/a + +# Add a few commits +seq 5 | while read i; do + echo a >> tree/root/a + ${CMD_PREFIX} ostree --repo=repo commit --branch=test-$i -m test -s test tree +done + +# Generate a plain summary file. +${CMD_PREFIX} ostree --repo=repo summary --update + +# Generate a signed summary file. +${CMD_PREFIX} ostree --repo=repo summary --update ${COMMIT_SIGN} + +# Try various ways of adding additional data. +${CMD_PREFIX} ostree --repo=repo summary --update --add-metadata key="'value'" --add-metadata=key2=true +${CMD_PREFIX} ostree --repo=repo summary --update -m some-int='@t 123' +${CMD_PREFIX} ostree --repo=repo summary --update --add-metadata=map='@a{sv} {}' + +# Check the additional metadata turns up in the output. +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_file_has_content summary "^map: {}$" + +echo "ok 1 update summary" + +# Test again, but with collections enabled in the repository. +cd ${test_tmpdir} +rm -rf repo +ostree_repo_init repo --collection-id org.example.Collection1 + +mkdir -p tree/root +touch tree/root/a + +# Add a few commits +seq 5 | while read i; do + echo a >> tree/root/a + ${CMD_PREFIX} ostree --repo=repo commit --branch=test-$i -m test -s test tree + ${CMD_PREFIX} ostree --repo=repo refs --collections --create=org.example.Collection2:test-$i test-$i +done + +# Generate a plain summary file. +${CMD_PREFIX} ostree --repo=repo summary --update + +# Generate a signed summary file. +${CMD_PREFIX} ostree --repo=repo summary --update ${COMMIT_SIGN} + +# Try various ways of adding additional data. +${CMD_PREFIX} ostree --repo=repo summary --update --add-metadata key="'value'" --add-metadata=key2=true +${CMD_PREFIX} ostree --repo=repo summary --update -m some-int='@t 123' +${CMD_PREFIX} ostree --repo=repo summary --update --add-metadata=map='@a{sv} {}' + +# Check the additional metadata turns up in the output. +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_file_has_content summary "^map: {}$" + +# Check the ostree-metadata ref has also been created with the same content and appropriate bindings. +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_file_has_content refs "^(org\.example\.Collection1, ostree-metadata)$" + +${CMD_PREFIX} ostree --repo=repo show ostree-metadata --raw > metadata +assert_file_has_content metadata "'map': <@a{sv} {}>" +assert_file_has_content metadata "'ostree\.ref-binding': <\['ostree-metadata'\]>" +assert_file_has_content metadata "'ostree\.collection-binding': <'org\.example\.Collection1'>" + +# There should be 5 commits in the ostree-metadata branch, since we’ve updated the summary 5 times. +${CMD_PREFIX} ostree --repo=repo log ostree-metadata | grep 'commit ' | wc -l > commit-count +assert_file_has_content commit-count "^5$" + +# The ostree-metadata commits should not contain any files +${CMD_PREFIX} ostree --repo=repo ls ostree-metadata > files +assert_file_has_content files " /$" +cat files | wc -l > files-count +assert_file_has_content files-count "^1$" + +echo "ok 2 update summary with collections" diff --git a/tests/test-summary-view.sh b/tests/test-summary-view.sh new file mode 100755 index 0000000..14de029 --- /dev/null +++ b/tests/test-summary-view.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Authors: +# - Philip Withnall + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..2" + +COMMIT_SIGN="" +if has_gpgme; then + COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" +fi + +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" + +# Set up a second branch. +mkdir ${test_tmpdir}/ostree-srv/other-files +cd ${test_tmpdir}/ostree-srv/other-files +echo 'hello world some object' > hello-world +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b other -s "A commit" -m "Example commit body" + +# Generate the summary file. +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u + +# Check out the repository. +prev_dir=`pwd` +cd ${test_tmpdir} +ostree_repo_init repo --mode=archive +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo pull --mirror origin + +# Check the summary file exists in the checkout, and can be viewed. +assert_has_file repo/summary +${OSTREE} summary --view > summary.txt +assert_file_has_content_literal summary.txt "* main" +assert_file_has_content_literal summary.txt "* other" +assert_file_has_content_literal summary.txt "ostree.summary.last-modified" +assert_file_has_content_literal summary.txt "Timestamp (ostree.commit.timestamp): " +echo "ok view summary" + +# Check the summary can be viewed raw too. +${OSTREE} summary --raw > raw-summary.txt +assert_file_has_content_literal raw-summary.txt "('main', (" +assert_file_has_content_literal raw-summary.txt "('other', (" +assert_file_has_content_literal raw-summary.txt "{'ostree.summary.last-modified': "$1/override_cmdline" + mount --bind "$1/override_cmdline" "$1/proc/cmdline" + + touch "$1/this_is_bootfs" + cp "${OSTREE_PREPARE_ROOT}" "$1/bin" +} + +setup_rootfs() { + mkdir -p "$1/ostree/deploy/linux/deploy/1334/sysroot" \ + "$1/ostree/deploy/linux/deploy/1334/var" \ + "$1/ostree/deploy/linux/deploy/1334/usr" \ + "$1/ostree/deploy/linux/var" \ + "$1/bin" + ln -s "deploy/linux/deploy/1334" "$1/ostree/boot.0" + ln -s . "$1/sysroot" + touch "$1/ostree/deploy/linux/deploy/1334/this_is_ostree_root" \ + "$1/ostree/deploy/linux/var/this_is_ostree_var" \ + "$1/ostree/deploy/linux/deploy/1334/usr/this_is_ostree_usr" \ + "$1/this_is_real_root" + cp /bin/busybox "$1/bin" + busybox --list | xargs -n1 -I '{}' ln -s busybox "$1/bin/{}" + cp -r "$1/bin" "$1/ostree/deploy/linux/deploy/1334/" +} + +setup_overlay() { + mkdir -p "$1/ostree/deploy/linux/deploy/1334/.usr-ovl-work" \ + "$1/ostree/deploy/linux/deploy/1334/.usr-ovl-upper" +} + +enter_fs() { + cd "$1" + mkdir testroot + pivot_root . testroot + export PATH=$PATH:/sysroot/bin + cd / + umount -l testroot + rmdir testroot +} + +find_in_env() { + tmpdir="$(mktemp -dt ostree-test-switchroot.XXXXXX)" + unshare -m <<-EOF + set -e + . "$this_script" + "$1" "$tmpdir" + enter_fs "$tmpdir" + ostree-prepare-root /sysroot + find / \( -path /proc -o -path /sysroot/proc \) -prune -o -print + touch /usr/usr_writable 2>/null \ + && echo "/usr is writable" \ + || echo "/usr is not writable" + touch /sysroot/usr/sysroot_usr_writable 2>/null \ + && echo "/sysroot/usr is writable" \ + || echo "/sysroot/usr is not writable" + EOF + (cd $tmpdir && find) >permanent_files + rm -rf "$tmpdir" +} + +setup_initrd_env() { + mount -t tmpfs tmpfs "$1" + setup_bootfs "$1" + mkdir "$1/sysroot" + mount -t tmpfs tmpfs "$1/sysroot" + setup_rootfs "$1/sysroot" +} + +test_that_prepare_root_sets_sysroot_up_correctly_with_initrd() { + find_in_env setup_initrd_env >files + + grep -qx "/this_is_bootfs" files + grep -qx "/sysroot/this_is_ostree_root" files + grep -qx "/sysroot/sysroot/this_is_real_root" files + if ! have_systemd_and_libmount; then + grep -qx "/sysroot/var/this_is_ostree_var" files + fi + grep -qx "/sysroot/usr/this_is_ostree_usr" files + + grep -qx "/sysroot/usr is not writable" files + echo "ok ostree-prepare-root sets sysroot up correctly with initrd" +} + +setup_no_initrd_env() { + mount --bind "$1" "$1" + setup_rootfs "$1" + setup_bootfs "$1" +} + +test_that_prepare_root_sets_root_up_correctly_with_no_initrd() { + find_in_env setup_no_initrd_env >files + + grep -qx "/this_is_ostree_root" files + grep -qx "/sysroot/this_is_bootfs" files + grep -qx "/sysroot/this_is_real_root" files + if ! have_systemd_and_libmount; then + grep -qx "/var/this_is_ostree_var" files + fi + grep -qx "/usr/this_is_ostree_usr" files + + grep -qx "/usr is not writable" files + echo "ok ostree-prepare-root sets root up correctly with no initrd" +} + +setup_no_initrd_with_overlay() { + setup_no_initrd_env "$1" + setup_overlay "$1" +} + +test_that_prepare_root_provides_overlay_over_usr_if__usr_ovl_work_exists() { + find_in_env setup_no_initrd_with_overlay >files + + grep -qx "/usr is writable" files + grep -qx "./ostree/deploy/linux/deploy/1334/.usr-ovl-upper/usr_writable" permanent_files + ! grep -qx "./ostree/deploy/linux/deploy/1334/usr/usr_writable" permanent_files || exit 1 + echo "ok ostree-prepare-root sets root up correctly with writable usr overlay" +} + +# This script sources itself so we only want to run tests if we're the parent: +if [ "${BASH_SOURCE[0]}" = "${0}" ]; then + . $(dirname $0)/libtest.sh + unshare -m true || \ + skip "this test needs to set up mount namespaces, rerun as root" + [ -f /bin/busybox ] || \ + skip "this test needs busybox" + + [ -n "${OSTREE_PREPARE_ROOT}" ] || \ + skip "this test needs ostree-prepare-root" + + echo "1..3" + test_that_prepare_root_sets_sysroot_up_correctly_with_initrd + test_that_prepare_root_sets_root_up_correctly_with_no_initrd + test_that_prepare_root_provides_overlay_over_usr_if__usr_ovl_work_exists +fi diff --git a/tests/test-symbols.sh b/tests/test-symbols.sh new file mode 100755 index 0000000..75df37e --- /dev/null +++ b/tests/test-symbols.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# +# Copyright (C) 2016 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -xeuo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..3' + +released_syms=${G_TEST_SRCDIR}/src/libostree/libostree-released.sym +if echo "$OSTREE_FEATURES" | grep --quiet --no-messages "devel"; then + devel_syms=${G_TEST_SRCDIR}/src/libostree/libostree-devel.sym +else + devel_syms= +fi +if echo "$OSTREE_FEATURES" | grep --quiet --no-messages "experimental"; then + experimental_sym="${G_TEST_SRCDIR}/src/libostree/libostree-experimental.sym" + experimental_sections="${G_TEST_SRCDIR}/apidoc/ostree-experimental-sections.txt" +else + experimental_sym="" + experimental_sections="" +fi + +echo "Verifying all expected symbols are actually exported..." +grep --no-filename ' ostree_[A-Za-z0-9_]*;' ${released_syms} ${devel_syms} ${experimental_sym} | sed -e 's,^ *\([A-Za-z0-9_]*\);,\1,' | sort -u > expected-symbols.txt +eu-readelf -a ${G_TEST_BUILDDIR}/.libs/libostree-1.so | grep 'FUNC.*GLOBAL.*DEFAULT.*@@LIBOSTREE_' | sed -e 's,^.* \(ostree_[A-Za-z0-9_]*\)@@LIBOSTREE_[0-9A-Z_.]*,\1,' |sort -u > found-symbols.txt +diff -u expected-symbols.txt found-symbols.txt + +echo "Checking that the example symbol wasn't copy-pasted..." +if test -f ${devel_syms}; then + assert_file_has_content_once ${devel_syms} "someostree_symbol_deleteme" +fi +if test -f ${experimental_sym}; then + assert_not_file_has_content ${experimental_sym} "someostree_symbol_deleteme" +fi +assert_not_file_has_content ${released_syms} "someostree_symbol_deleteme" + +echo "ok exports" + +# cmd__private__ is private. The fetcher symbol should not have been made public. +grep -E -v '(ostree_cmd__private__)|(ostree_fetcher_config_flags_get_type)' found-symbols.txt > expected-documented.txt + +echo "Verifying all public symbols are documented:" +grep --no-filename '^ostree_' ${G_TEST_SRCDIR}/apidoc/ostree-sections.txt $experimental_sections |sort -u > found-documented.txt +diff -u expected-documented.txt found-documented.txt + +echo 'ok documented symbols' + +# ONLY update this checksum in release commits! +cat > released-sha256.txt < +#include +#include + +#include "libglnx.h" +#include "libostreetest.h" + +static gboolean +run_sync (const char *cmdline, GError **error) +{ + int estatus; + if (!g_spawn_command_line_sync (cmdline, NULL, NULL, &estatus, error)) + return FALSE; + if (!g_spawn_check_exit_status (estatus, error)) + return FALSE; + return TRUE; +} + +static void +test_sysroot_reload (gconstpointer data) +{ + OstreeSysroot *sysroot = (void*)data; + g_autoptr(GError) error = NULL; + gboolean changed; + + if (!ostree_sysroot_load (sysroot, NULL, &error)) + goto out; + + if (!ostree_sysroot_load_if_changed (sysroot, &changed, NULL, &error)) + goto out; + g_assert (!changed); + + if (!run_sync ("ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime", &error)) + goto out; + + if (!run_sync ("ostree admin --sysroot=sysroot deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime", &error)) + goto out; + + if (!ostree_sysroot_load_if_changed (sysroot, &changed, NULL, &error)) + goto out; + g_assert (changed); + + if (!ostree_sysroot_load_if_changed (sysroot, &changed, NULL, &error)) + goto out; + g_assert (!changed); + + out: + if (error) + g_error ("%s", error->message); +} + +int main (int argc, char **argv) +{ + g_autoptr(GError) error = NULL; + glnx_unref_object OstreeSysroot *sysroot = NULL; + + g_test_init (&argc, &argv, NULL); + + sysroot = ot_test_setup_sysroot (NULL, &error); + if (!sysroot) + goto out; + + g_test_add_data_func ("/sysroot-reload", sysroot, test_sysroot_reload); + + return g_test_run(); + out: + if (error) + g_error ("%s", error->message); + return 1; +} diff --git a/tests/test-sysroot.js b/tests/test-sysroot.js new file mode 100755 index 0000000..d27c6e1 --- /dev/null +++ b/tests/test-sysroot.js @@ -0,0 +1,155 @@ +#!/usr/bin/env gjs +// +// Copyright (C) 2013 Colin Walters +// +// SPDX-License-Identifier: LGPL-2.0+ +// +// 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 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., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; +const OSTree = imports.gi.OSTree; + +function assertEquals(a, b) { + if (a != b) + throw new Error("assertion failed " + JSON.stringify(a) + " == " + JSON.stringify(b)); +} + +function assertNotEquals(a, b) { + if (a == b) + throw new Error("assertion failed " + JSON.stringify(a) + " != " + JSON.stringify(b)); +} + +function libtestExec(shellCode) { + let testdatadir = GLib.getenv("G_TEST_SRCDIR"); + let libtestPath = GLib.build_filenamev([testdatadir, 'tests/libtest.sh']) + let proc = Gio.Subprocess.new(['bash', '-c', 'set -xeuo pipefail; . ' + GLib.shell_quote(libtestPath) + '; ' + shellCode], 0); + proc.wait_check(null); +} + +print('1..1') + +libtestExec('setup_os_repository archive syslinux'); + +GLib.setenv("OSTREE_SYSROOT_DEBUG", "mutable-deployments", true); + +let upstreamRepo = OSTree.Repo.new(Gio.File.new_for_path('testos-repo')); +upstreamRepo.open(null); + +let runtimeRef = 'testos/buildmaster/x86_64-runtime'; +let [,rev] = upstreamRepo.resolve_rev(runtimeRef, false); + +print("testos => " + rev); + +//// TEST: We should have no deployments + +let sysroot = OSTree.Sysroot.new(Gio.File.new_for_path('sysroot')); +sysroot.load(null); +let deployments = sysroot.get_deployments(); +assertEquals(deployments.length, 0); + +//// Add the remote, and do a pull + +let [,sysrootRepo] = sysroot.get_repo(null); +sysrootRepo.remote_add('testos', 'file://' + upstreamRepo.get_path().get_path(), + GLib.Variant.new('a{sv}', {'gpg-verify': GLib.Variant.new('b', false), + 'branches': GLib.Variant.new('as', [runtimeRef])}), null); +sysrootRepo.pull('testos', null, 0, null, null); + +//// TEST: We can deploy one tree + +let mergeDeployment = sysroot.get_merge_deployment('testos'); + +let origin = sysroot.origin_new_from_refspec(runtimeRef); +let [,deployment] = sysroot.deploy_tree('testos', rev, origin, + mergeDeployment, null, + null); +let newDeployments = deployments; +deployments = null; +newDeployments.unshift(deployment); +sysroot.write_deployments(newDeployments, null); +deployments = sysroot.get_deployments(); +assertEquals(deployments.length, newDeployments.length); +assertEquals(deployments[0].get_csum(), deployment.get_csum()); + +let deploymentPath = sysroot.get_deployment_directory(deployment); +assertEquals(deploymentPath.query_exists(null), true); + +print("OK one deployment"); + +/// TEST: We can delete the deployment, going back to empty +sysroot.write_deployments([], null); + +print("OK empty deployments"); + +assertEquals(deploymentPath.query_exists(null), false); + +//// Ok, redeploy, then add a new revision upstream and pull it + +[,deployment] = sysroot.deploy_tree('testos', rev, origin, + mergeDeployment, null, + null); +newDeployments = deployments; +deployments = null; +newDeployments.unshift(deployment); +print(JSON.stringify(newDeployments)); +sysroot.write_deployments(newDeployments, null); + +libtestExec('os_repository_new_commit'); + +sysrootRepo.pull('testos', null, 0, null, null); + +let [,newRev] = upstreamRepo.resolve_rev(runtimeRef, false); + +print("testos => " + newRev); +assertNotEquals(rev, newRev); + +mergeDeployment = sysroot.get_merge_deployment('testos'); +assertEquals(mergeDeployment.get_csum(), deployment.get_csum()); +let [,newDeployment] = sysroot.deploy_tree('testos', newRev, origin, + mergeDeployment, null, + null); +newDeployments = [newDeployment, mergeDeployment]; +assertNotEquals(mergeDeployment.get_bootcsum(), newDeployment.get_bootcsum()); +assertNotEquals(mergeDeployment.get_csum(), newDeployment.get_csum()); +sysroot.write_deployments(newDeployments, null); +deployments = sysroot.get_deployments(); +assertEquals(deployments.length, 2); +assertEquals(deploymentPath.query_exists(null), true); +let newDeploymentPath = sysroot.get_deployment_directory(newDeployment); +assertEquals(newDeploymentPath.query_exists(null), true); + +print("OK two deployments"); + +libtestExec('os_repository_new_commit 0 1'); + +sysrootRepo.pull('testos', null, 0, null, null); + +let [,thirdRev] = sysrootRepo.resolve_rev(runtimeRef, false); +assertNotEquals(newRev, thirdRev); + +mergeDeployment = sysroot.get_merge_deployment('testos'); +let [,thirdDeployment] = sysroot.deploy_tree('testos', thirdRev, origin, + mergeDeployment, null, + null); +assertEquals(mergeDeployment.get_bootcsum(), thirdDeployment.get_bootcsum()); +assertNotEquals(mergeDeployment.get_csum(), thirdDeployment.get_csum()); +newDeployments = [deployment, newDeployment, thirdDeployment]; +sysroot.write_deployments(newDeployments, null); +deployments = sysroot.get_deployments(); +assertEquals(deployments.length, 3); + +print("ok test-sysroot") diff --git a/tests/test-varint.c b/tests/test-varint.c new file mode 100644 index 0000000..605b743 --- /dev/null +++ b/tests/test-varint.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.0+ + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libglnx.h" + +#include "ostree-varint.h" + +static void +check_one_roundtrip (guint64 val) +{ + g_autoptr(GString) buf = g_string_new (NULL); + guint64 newval; + gsize bytes_read; + + _ostree_write_varuint64 (buf, val); + if (g_test_verbose ()) + { + g_autoptr(GVariant) v = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), buf->str, buf->len, TRUE, NULL, NULL); + g_autofree char *data = g_variant_print (v, FALSE); + g_test_message ("%" G_GUINT64_FORMAT " -> %s", val, data); + } + g_assert (_ostree_read_varuint64 ((guint8*)buf->str, buf->len, &newval, &bytes_read)); + g_assert_cmpint (bytes_read, <=, 10); + g_assert_cmpint (val, ==, newval); +} + +static void +test_roundtrips (void) +{ + const guint64 test_inputs[] = { 0, 1, 0x6F, 0xA0, 0xFF, 0xF0F0, 0xCAFE, + 0xCAFEBABE, G_MAXUINT64, G_MAXUINT64-1, + G_MAXUINT64 / 2}; + guint i; + + for (i = 0; i < G_N_ELEMENTS (test_inputs); i++) + check_one_roundtrip (test_inputs[i]); +} + +int +main (int argc, char **argv) +{ + + g_setenv ("GIO_USE_VFS", "local", TRUE); + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/ostree/varint", test_roundtrips); + + return g_test_run (); +} diff --git a/tests/test-xattrs.sh b/tests/test-xattrs.sh new file mode 100755 index 0000000..07c9ac3 --- /dev/null +++ b/tests/test-xattrs.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Copyright (C) 2013 Colin Walters +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# 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 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +skip "We don't really have a use case for committing user. xattrs right now. See also https://github.com/ostreedev/ostree/issues/758" + +# Dead code below +skip_without_user_xattrs + +echo "1..2" + +setup_test_repository "archive" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=repo checkout test2 test2-checkout1 +setfattr -n user.ostree-test -v testvalue test2-checkout1/firstfile +setfattr -n user.test0 -v moo test2-checkout1/firstfile +${CMD_PREFIX} ostree --repo=repo commit -b test2 -s xattrs --tree=dir=test2-checkout1 +rm test2-checkout1 -rf +echo "ok commit with xattrs" + +${CMD_PREFIX} ostree --repo=repo checkout test2 test2-checkout2 +getfattr -m . test2-checkout2/firstfile > attrs +assert_file_has_content attrs '^user\.ostree-test' +assert_file_has_content attrs '^user\.test0' +getfattr -n user.ostree-test --only-values test2-checkout2/firstfile > v0 +assert_file_has_content v0 '^testvalue$' +getfattr -n user.test0 --only-values test2-checkout2/firstfile > v1 +assert_file_has_content v1 '^moo$' +echo "ok checkout with xattrs"