diff options
| author | Michael Biebl <biebl@debian.org> | 2015-01-22 00:29:39 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2015-01-22 00:29:39 +0100 |
| commit | 2c032d8f1c6292c1338a615e6ec40252889ba85c (patch) | |
| tree | 1f77182220b2b0264288ba4a476ab47e5bc48716 /libgsystem | |
| parent | 33491bc4279481db8ae47213e34a6d695a0e8830 (diff) | |
Imported Upstream version 1.0.0 upstream/1.0.0
Diffstat (limited to 'libgsystem')
| -rw-r--r-- | libgsystem/COPYING | 481 | ||||
| -rw-r--r-- | libgsystem/Makefile-libgsystem.am | 42 | ||||
| -rw-r--r-- | libgsystem/README | 10 | ||||
| -rw-r--r-- | libgsystem/gsystem-console.c | 443 | ||||
| -rw-r--r-- | libgsystem/gsystem-console.h | 59 | ||||
| -rw-r--r-- | libgsystem/gsystem-file-utils.c | 1644 | ||||
| -rw-r--r-- | libgsystem/gsystem-file-utils.h | 172 | ||||
| -rw-r--r-- | libgsystem/gsystem-glib-compat.h | 54 | ||||
| -rw-r--r-- | libgsystem/gsystem-local-alloc.c | 72 | ||||
| -rw-r--r-- | libgsystem/gsystem-local-alloc.h | 164 | ||||
| -rw-r--r-- | libgsystem/gsystem-log.c | 167 | ||||
| -rw-r--r-- | libgsystem/gsystem-log.h | 42 | ||||
| -rw-r--r-- | libgsystem/gsystem-shutil.c | 460 | ||||
| -rw-r--r-- | libgsystem/gsystem-shutil.h | 47 | ||||
| -rw-r--r-- | libgsystem/gsystem-subprocess-context-private.h | 65 | ||||
| -rw-r--r-- | libgsystem/gsystem-subprocess-context.c | 501 | ||||
| -rw-r--r-- | libgsystem/gsystem-subprocess-context.h | 128 | ||||
| -rw-r--r-- | libgsystem/gsystem-subprocess.c | 966 | ||||
| -rw-r--r-- | libgsystem/gsystem-subprocess.h | 101 | ||||
| -rw-r--r-- | libgsystem/libgsystem.h | 49 |
20 files changed, 0 insertions, 5667 deletions
diff --git a/libgsystem/COPYING b/libgsystem/COPYING deleted file mode 100644 index 5bc8fb2c..00000000 --- a/libgsystem/COPYING +++ /dev/null @@ -1,481 +0,0 @@ - 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. - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU 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. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/libgsystem/Makefile-libgsystem.am b/libgsystem/Makefile-libgsystem.am deleted file mode 100644 index 092522c7..00000000 --- a/libgsystem/Makefile-libgsystem.am +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2012 Colin Walters <walters@verbum.org> -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# 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 += $(libgsystem_srcpath)/README $(libgsystem_srcpath)/COPYING - -libgsystem_la_SOURCES = \ - $(libgsystem_srcpath)/gsystem-local-alloc.h \ - $(libgsystem_srcpath)/gsystem-local-alloc.c \ - $(libgsystem_srcpath)/gsystem-console.h \ - $(libgsystem_srcpath)/gsystem-console.c \ - $(libgsystem_srcpath)/gsystem-file-utils.h \ - $(libgsystem_srcpath)/gsystem-file-utils.c \ - $(libgsystem_srcpath)/gsystem-glib-compat.h \ - $(libgsystem_srcpath)/gsystem-shutil.h \ - $(libgsystem_srcpath)/gsystem-shutil.c \ - $(libgsystem_srcpath)/gsystem-log.h \ - $(libgsystem_srcpath)/gsystem-log.c \ - $(libgsystem_srcpath)/gsystem-subprocess-context.h \ - $(libgsystem_srcpath)/gsystem-subprocess-context-private.h \ - $(libgsystem_srcpath)/gsystem-subprocess-context.c \ - $(libgsystem_srcpath)/gsystem-subprocess.h \ - $(libgsystem_srcpath)/gsystem-subprocess.c \ - $(libgsystem_srcpath)/libgsystem.h \ - $(NULL) - -libgsystem_la_CFLAGS = $(AM_CFLAGS) $(libgsystem_cflags) -libgsystem_la_LDFLAGS = -avoid-version -Bsymbolic-functions -export-symbols-regex "^gs_" -no-undefined -export-dynamic -libgsystem_la_LIBADD = $(libgsystem_libs) diff --git a/libgsystem/README b/libgsystem/README deleted file mode 100644 index 13fa05f2..00000000 --- a/libgsystem/README +++ /dev/null @@ -1,10 +0,0 @@ -libgsystem is intended to be used as a git external for components -that depend on GLib, but accept a hard dependency on things which are -difficult to do in GLib itself. For example, the local-alloc API -depends on GCC/clang. - -It will also be a useful place to evolve new APIs (e.g. logging) -before their eventual inclusion in GLib (if ever). - -There's no bugzilla component currently, please mail -patches to: walters@verbum.org diff --git a/libgsystem/gsystem-console.c b/libgsystem/gsystem-console.c deleted file mode 100644 index 35477eba..00000000 --- a/libgsystem/gsystem-console.c +++ /dev/null @@ -1,443 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2013 Colin Walters <walters@verbum.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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" - -#define _GSYSTEM_NO_LOCAL_ALLOC -#include "libgsystem.h" - -/** - * SECTION:gsconsole - * @title: GSConsole - * @short_description: Interact with standard input/output as well as terminal - * - * First, this class offers API to access the standard input and - * output/error, streams as #GInputStream and #GOutputStream - * respectively. - * - * In the case where the process is connected to a controlling - * terminal, the gs_console_get() API is available, which exposes a - * number of additional features such as no-echo password reading. - * - * Since: 2.36 - */ - -#include "config.h" - -#include "gsystem-console.h" - -#include <string.h> -#ifdef G_OS_UNIX -#include <gio/gunixoutputstream.h> -#include <gio/gfiledescriptorbased.h> -#include <gio/gunixinputstream.h> -#include <glib-unix.h> -#include <unistd.h> -#include <termios.h> -#endif -#include <fcntl.h> - -typedef GObjectClass GSConsoleClass; - -struct _GSConsole -{ - GObject parent; - - gboolean in_status_line; - gssize last_line_written; -}; - -G_DEFINE_TYPE (GSConsole, gs_console, G_TYPE_OBJECT); - -static void -gs_console_init (GSConsole *self) -{ - self->last_line_written = -1; -} - -static void -gs_console_class_init (GSConsoleClass *class) -{ -} - -/** - * gs_console_get: - * - * If the current process has an interactive console, return the - * singleton #GSConsole instance. On Unix, this is equivalent to - * isatty(). For all other cases, such as pipes, sockets, /dev/null, - * this function will return %NULL. - * - * Returns: (transfer none): The console instance, or %NULL if not interactive - * - * Since: 2.36 - */ -GSConsole * -gs_console_get (void) -{ - static gsize checked = 0; - static GSConsole *instance = NULL; - - if (g_once_init_enter (&checked)) - { -#ifdef G_OS_UNIX - if (isatty (0) && isatty (1)) - instance = g_object_new (GS_TYPE_CONSOLE, NULL); -#endif - g_once_init_leave (&checked, 1); - } - - return (GSConsole*) instance; -} - -/** - * gs_console_get_stdin: - * - * Returns: (transfer none): The singleton stream connected to standard input - */ -GInputStream * -gs_console_get_stdin (void) -{ -#ifdef G_OS_UNIX - static gsize instance = 0; - - if (g_once_init_enter (&instance)) - g_once_init_leave (&instance, (gsize) g_unix_input_stream_new (0, FALSE)); - - return (GInputStream*) instance; -#else - g_error ("not implemented"); -#endif -} - -/** - * gs_console_get_stdout: - * - * Returns: (transfer none): The singleton stream connected to standard output - */ -GOutputStream * -gs_console_get_stdout (void) -{ -#ifdef G_OS_UNIX - static gsize instance = 0; - - if (g_once_init_enter (&instance)) - g_once_init_leave (&instance, (gsize) g_unix_output_stream_new (1, FALSE)); - - return (GOutputStream*) instance; -#else - g_error ("not implemented"); -#endif -} - -/** - * gs_console_get_stderr: - * - * Returns: (transfer none): The singleton stream connected to standard error - */ -GOutputStream * -gs_console_get_stderr (void) -{ -#ifdef G_OS_UNIX - static gsize instance = 0; - - if (g_once_init_enter (&instance)) - g_once_init_leave (&instance, (gsize) g_unix_output_stream_new (2, FALSE)); - - return (GOutputStream*) instance; -#else - g_error ("not implemented"); -#endif -} - -#ifdef G_OS_UNIX -static inline void -_set_error_from_errno (GError **error) -{ - int errsv = errno; - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); -} -#endif - -/** - * gs_console_read_password: - * @console: the #GSConsole - * @prompt: A string to output before reading the password - * @error: a #GError - * - * Write @prompt to standard output, then switch output echo off, read - * a result string, then switch output echo back on. - * - * Returns: A string, or %NULL on error - */ -char * -gs_console_read_password (GSConsole *console, - const char *prompt, - GCancellable *cancellable, - GError **error) -{ -#ifdef G_OS_UNIX - gboolean ret = FALSE; - /* This code is modified from that found in - * polkit/src/polkittextagentlistener.c, reused under the LGPL v2.1 - */ - int res; - struct termios ts, ots; - GInputStream *in; - GOutputStream *out; - GString *str = NULL; - gsize bytes_written; - gboolean reset_terminal = FALSE; - - in = gs_console_get_stdin (); - out = gs_console_get_stdout (); - - if (!g_output_stream_write_all (out, prompt, strlen (prompt), &bytes_written, - cancellable, error)) - goto out; - if (!g_output_stream_flush (out, cancellable, error)) - goto out; - - /* TODO: We really ought to block SIGINT and STGSTP (and probably - * other signals too) so we can restore the terminal (since we - * turn off echoing). See e.g. Advanced Programming in the - * UNIX Environment 2nd edition (Steves and Rago) section - * 18.10, pg 660 where this is suggested. See also various - * getpass(3) implementations - * - * However, since we are a library routine the user could have - * multiple threads - in fact, typical usage of - * PolkitAgentTextListener is to run it in a thread. And - * unfortunately threads and POSIX signals is a royal PITA. - * - * Maybe we could fork(2) and ask for the password in the - * child and send it back to the parent over a pipe? (we are - * guaranteed that there is only one thread in the child - * process). - * - * (Side benefit of doing this in a child process is that we - * could avoid blocking the thread where the - * PolkitAgentTextListener object is being serviced from. But - * since this class is normally used in a dedicated thread - * it doesn't really matter *anyway*.) - * - * Anyway, On modern Linux not doing this doesn't seem to be a - * problem - looks like modern shells restore echoing anyway - * on the first input. So maybe it's not even worth solving - * the problem. - */ - - do - res = tcgetattr (1, &ts); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1) - { - _set_error_from_errno (error); - goto out; - } - ots = ts; - ts.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); - do - res = tcsetattr (1, TCSAFLUSH, &ts); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1) - { - _set_error_from_errno (error); - goto out; - } - - /* After this point, we'll need to clean up the terminal in case of - * error. - */ - reset_terminal = TRUE; - - str = g_string_new (NULL); - while (TRUE) - { - gssize bytes_read; - guint8 buf[1]; - - /* FIXME - we should probably be converting from the system - * codeset, in case it's not UTF-8. - */ - bytes_read = g_input_stream_read (in, buf, sizeof (buf), - cancellable, error); - if (bytes_read < 0) - goto out; - else if (bytes_read == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - "End of stream while reading password"); - goto out; - } - else if (buf[0] == '\n') - { - break; - } - else - { - g_string_append_c (str, buf[0]); - } - } - - ret = TRUE; - out: - if (reset_terminal) - { - do - res = tcsetattr (1, TCSAFLUSH, &ots); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1) - { - _set_error_from_errno (error); - g_string_free (str, TRUE); - return NULL; - } - } - - if (!ret) - { - g_string_free (str, TRUE); - return NULL; - } - else - { - return g_string_free (str, FALSE); - } -#else - g_error ("not implemented"); -#endif -} - -/** - * gs_console_begin_status_line: - * @console: the #GSConsole - * @line: String to output - * - * The primary use case for this function is to output periodic - * "status" or "progress" information. The first time this function - * is called, @line will be output normally. Subsequent invocations - * will overwrite the previous. - * - * You must invoke gs_console_end_status_line() to return the console - * to normal mode. In particular, concurrent use of this function and - * the stream returned by gs_console_get_stdout() results in undefined - * behavior. - */ -gboolean -gs_console_begin_status_line (GSConsole *console, - const char *line, - GCancellable *cancellable, - GError **error) -{ -#ifdef G_OS_UNIX - gboolean ret = FALSE; - gsize linelen; - GOutputStream *out; - gsize bytes_written; - - out = gs_console_get_stdout (); - - if (!console->in_status_line) - { - guint8 buf[3] = { (guint8)'\n', 0x1B, 0x37 }; - if (!g_output_stream_write_all (out, buf, sizeof (buf), &bytes_written, - cancellable, error)) - goto out; - console->in_status_line = TRUE; - console->last_line_written = -1; - } - - { - guint8 buf[2] = { 0x1B, 0x38 }; - if (!g_output_stream_write_all (out, buf, sizeof (buf), &bytes_written, - cancellable, error)) - goto out; - } - - linelen = strlen (line); - if (!g_output_stream_write_all (out, line, linelen, &bytes_written, - cancellable, error)) - goto out; - - /* Now we need to pad with spaces enough to overwrite our last line - */ - if (console->last_line_written >= 0 - && linelen < (gsize) console->last_line_written) - { - gsize towrite = console->last_line_written - linelen; - const char c = ' '; - while (towrite > 0) - { - if (!g_output_stream_write_all (out, &c, 1, &bytes_written, - cancellable, error)) - goto out; - towrite--; - } - } - - console->last_line_written = linelen; - - ret = TRUE; - out: - return ret; -#else - g_error ("not implemented"); -#endif -} - -/** - * gs_console_end_status_line: - * @console: the #GSConsole - * - * Complete a series of invocations of gs_console_begin_status_line(), - * returning the stream to normal mode. The last printed status line - * remains on the console; if this is not desired, print an empty - * string to clear it before invoking this function. - */ -gboolean -gs_console_end_status_line (GSConsole *console, - GCancellable *cancellable, - GError **error) -{ -#ifdef G_OS_UNIX - gboolean ret = FALSE; - GOutputStream *out; - gsize bytes_written; - char c = '\n'; - - g_return_val_if_fail (console->in_status_line, FALSE); - - out = gs_console_get_stdout (); - - if (!g_output_stream_write_all (out, &c, 1, &bytes_written, - cancellable, error)) - goto out; - - console->in_status_line = FALSE; - - ret = TRUE; - out: - return ret; -#else - g_error ("not implemented"); -#endif -} diff --git a/libgsystem/gsystem-console.h b/libgsystem/gsystem-console.h deleted file mode 100644 index a22b2d45..00000000 --- a/libgsystem/gsystem-console.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2013 Colin Walters <walters@verbum.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 __GSYSTEM_CONSOLE_H__ -#define __GSYSTEM_CONSOLE_H__ - -#include <gio/gio.h> - -G_BEGIN_DECLS - -#define GS_TYPE_CONSOLE (gs_console_get_type ()) -#define GS_CONSOLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_CONSOLE, GSConsole)) -#define GS_IS_CONSOLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_CONSOLE)) - -typedef struct _GSConsole GSConsole; - -GType gs_console_get_type (void) G_GNUC_CONST; - -GInputStream * gs_console_get_stdin (void); -GOutputStream * gs_console_get_stdout (void); -GOutputStream * gs_console_get_stderr (void); - -GSConsole * gs_console_get (void); - -char * gs_console_read_password (GSConsole *console, - const char *prompt, - GCancellable *cancellable, - GError **error); - -gboolean gs_console_begin_status_line (GSConsole *console, - const char *line, - GCancellable *cancellable, - GError **error); - -gboolean gs_console_end_status_line (GSConsole *console, - GCancellable *cancellable, - GError **error); - - -G_END_DECLS - -#endif diff --git a/libgsystem/gsystem-file-utils.c b/libgsystem/gsystem-file-utils.c deleted file mode 100644 index 02606035..00000000 --- a/libgsystem/gsystem-file-utils.c +++ /dev/null @@ -1,1644 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 William Jon McCann <mccann@redhat.com> - * Copyright (C) 2012 Colin Walters <walters@verbum.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include <string.h> - -#define _GSYSTEM_NO_LOCAL_ALLOC -#include "libgsystem.h" -#include "gsystem-glib-compat.h" -#include <glib/gstdio.h> -#include <gio/gunixinputstream.h> -#include <gio/gfiledescriptorbased.h> -#include <gio/gunixoutputstream.h> -#include <glib-unix.h> -#include <limits.h> -#include <dirent.h> -#ifdef GSYSTEM_CONFIG_XATTRS -#include <attr/xattr.h> -#endif - -static int -close_nointr (int fd) -{ - int res; - /* Note this is NOT actually a retry loop. - * See: https://bugzilla.gnome.org/show_bug.cgi?id=682819 - */ - res = close (fd); - /* Just ignore EINTR...on Linux, retrying is wrong. */ - if (res == EINTR) - res = 0; - return res; -} - -static void -close_nointr_noerror (int fd) -{ - (void) close_nointr (fd); -} - -static int -open_nointr (const char *path, int flags, mode_t mode) -{ - int res; - do - res = open (path, flags, mode); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - return res; -} - -static inline void -_set_error_from_errno (GError **error) -{ - int errsv = errno; - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); -} - -/** - * gs_file_openat_noatime: - * @dfd: File descriptor for directory - * @name: Pathname, relative to @dfd - * @ret_fd: (out): Returned file descriptor - * @cancellable: Cancellable - * @error: Error - * - * Wrapper for openat() using %O_RDONLY with %O_NOATIME if available. - */ -gboolean -gs_file_openat_noatime (int dfd, - const char *name, - int *ret_fd, - GCancellable *cancellable, - GError **error) -{ - int fd; - -#ifdef O_NOATIME - do - fd = openat (dfd, name, O_RDONLY | O_NOATIME, 0); - while (G_UNLIKELY (fd == -1 && errno == EINTR)); - /* Only the owner or superuser may use O_NOATIME; so we may get - * EPERM. EINVAL may happen if the kernel is really old... - */ - if (fd == -1 && (errno == EPERM || errno == EINVAL)) -#endif - do - fd = openat (dfd, name, O_RDONLY, 0); - while (G_UNLIKELY (fd == -1 && errno == EINTR)); - - if (fd == -1) - { - _set_error_from_errno (error); - return FALSE; - } - else - { - *ret_fd = fd; - return TRUE; - } -} - -/** - * gs_file_read_noatime: - * @file: a #GFile - * @cancellable: a #GCancellable - * @error: a #GError - * - * Like g_file_read(), but try to avoid updating the file's - * access time. This should be used by background scanning - * components such as search indexers, antivirus programs, etc. - * - * Returns: (transfer full): A new input stream, or %NULL on error - */ -GInputStream * -gs_file_read_noatime (GFile *file, - GCancellable *cancellable, - GError **error) -{ - const char *path = NULL; - int fd; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return NULL; - - path = gs_file_get_path_cached (file); - if (path == NULL) - { - char *uri; - uri = g_file_get_uri (file); - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, - "%s has no associated path", uri); - g_free (uri); - return NULL; - } - - if (!gs_file_openat_noatime (AT_FDCWD, path, &fd, cancellable, error)) - return NULL; - - return g_unix_input_stream_new (fd, TRUE); -} - -/** - * gs_stream_fstat: - * @stream: A stream containing a Unix file descriptor - * @stbuf: Memory location to write stat buffer - * @cancellable: - * @error: - * - * Some streams created via libgsystem are #GUnixInputStream; these do - * not support e.g. g_file_input_stream_query_info(). This function - * allows dropping to the raw unix fstat() call for these types of - * streams, while still conveniently wrapped with the normal GLib - * handling of @cancellable and @error. - */ -gboolean -gs_stream_fstat (GFileDescriptorBased *stream, - struct stat *stbuf, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int fd; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto out; - - fd = g_file_descriptor_based_get_fd (stream); - - if (fstat (fd, stbuf) == -1) - { - _set_error_from_errno (error); - goto out; - } - - ret = TRUE; - out: - return ret; -} - -/** - * gs_file_map_noatime: (skip) - * @file: a #GFile - * @cancellable: a #GCancellable - * @error: a #GError - * - * Like g_mapped_file_new(), but try to avoid updating the file's - * access time. This should be used by background scanning - * components such as search indexers, antivirus programs, etc. - * - * Returns: (transfer full): A new mapped file, or %NULL on error - */ -GMappedFile * -gs_file_map_noatime (GFile *file, - GCancellable *cancellable, - GError **error) -{ - const char *path; - int fd; - GMappedFile *ret; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return NULL; - - path = gs_file_get_path_cached (file); - if (path == NULL) - return NULL; - - if (!gs_file_openat_noatime (AT_FDCWD, path, &fd, cancellable, error)) - return NULL; - - ret = g_mapped_file_new_from_fd (fd, FALSE, error); - close_nointr_noerror (fd); /* Ignore errors - we always want to close */ - - return ret; -} - -#if GLIB_CHECK_VERSION(2,34,0) -/** - * gs_file_map_readonly: - * @file: a #GFile - * @cancellable: - * @error: - * - * Return a #GBytes which references a readonly view of the contents of - * @file. This function uses #GMappedFile internally. - * - * Returns: (transfer full): a newly referenced #GBytes - */ -GBytes * -gs_file_map_readonly (GFile *file, - GCancellable *cancellable, - GError **error) -{ - GMappedFile *mfile; - GBytes *ret; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return NULL; - - mfile = g_mapped_file_new (gs_file_get_path_cached (file), FALSE, error); - if (!mfile) - return NULL; - - ret = g_mapped_file_get_bytes (mfile); - g_mapped_file_unref (mfile); - return ret; -} -#endif - -/** - * gs_file_sync_data: - * @file: a #GFile - * @cancellable: - * @error: - * - * Wraps the UNIX fsync() function (or fdatasync(), if available), which - * ensures that the data in @file is on non-volatile storage. - */ -gboolean -gs_file_sync_data (GFile *file, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int res; - int fd = -1; - - if (!gs_file_openat_noatime (AT_FDCWD, gs_file_get_path_cached (file), &fd, - cancellable, error)) - goto out; - - do - { -#ifdef __linux - res = fdatasync (fd); -#else - res = fsync (fd); -#endif - } - while (G_UNLIKELY (res != 0 && errno == EINTR)); - if (res != 0) - { - _set_error_from_errno (error); - goto out; - } - - res = close_nointr (fd); - if (res != 0) - { - _set_error_from_errno (error); - goto out; - } - fd = -1; - - ret = TRUE; - out: - if (fd != -1) - close_nointr_noerror (fd); - return ret; -} - -/** - * gs_file_create: - * @file: Path to non-existent file - * @mode: Unix access permissions - * @out_stream: (out) (transfer full) (allow-none): Newly created output, or %NULL - * @cancellable: a #GCancellable - * @error: a #GError - * - * Like g_file_create(), except this function allows specifying the - * access mode. This allows atomically creating private files. - */ -gboolean -gs_file_create (GFile *file, - int mode, - GOutputStream **out_stream, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int fd; - GOutputStream *ret_stream = NULL; - - fd = open_nointr (gs_file_get_path_cached (file), O_WRONLY | O_CREAT | O_EXCL, mode); - if (fd < 0) - { - _set_error_from_errno (error); - goto out; - } - - if (fchmod (fd, mode) < 0) - { - close (fd); - _set_error_from_errno (error); - goto out; - } - - ret_stream = g_unix_output_stream_new (fd, TRUE); - - ret = TRUE; - gs_transfer_out_value (out_stream, &ret_stream); - out: - g_clear_object (&ret_stream); - return ret; -} - -static const char * -get_default_tmp_prefix (void) -{ - static char *tmpprefix = NULL; - - if (g_once_init_enter (&tmpprefix)) - { - const char *prgname = g_get_prgname (); - const char *p; - char *prefix; - char *iter; - - if (prgname) - { - p = strrchr (prgname, '/'); - if (p) - prgname = p + 1; - } - else - prgname = ""; - - prefix = g_strdup_printf ("tmp-%s%u-", prgname, getuid ()); - for (iter = prefix; *iter; iter++) - { - char c = *iter; - if (c == ' ') - *iter = '_'; - } - - g_once_init_leave (&tmpprefix, prefix); - } - - return tmpprefix; -} - -/** - * gs_fileutil_gen_tmp_name: - * @prefix: (allow-none): String prepended to the result - * @suffix: (allow-none): String suffixed to the result - * - * Generate a name suitable for use as a temporary file. This - * function does no I/O; it is not guaranteed that a file with that - * name does not exist. - */ -char * -gs_fileutil_gen_tmp_name (const char *prefix, - const char *suffix) -{ - static const char table[] = "ABCEDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789"; - GString *str = g_string_new (""); - guint i; - - if (!prefix) - prefix = get_default_tmp_prefix (); - if (!suffix) - suffix = "tmp"; - - g_string_append (str, prefix); - for (i = 0; i < 8; i++) - { - int offset = g_random_int_range (0, sizeof (table) - 1); - g_string_append_c (str, (guint8)table[offset]); - } - g_string_append_c (str, '.'); - g_string_append (str, suffix); - - return g_string_free (str, FALSE); -} - -/** - * gs_file_open_dir_fd: - * @path: Directory name - * @out_fd: (out): File descriptor for directory - * @cancellable: Cancellable - * @error: Error - * - * On success, sets @out_fd to a file descriptor for the directory - * that can be used with UNIX functions such as openat(). - */ -gboolean -gs_file_open_dir_fd (GFile *path, - int *out_fd, - GCancellable *cancellable, - GError **error) -{ - /* Linux specific probably */ - *out_fd = open (gs_file_get_path_cached (path), O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC); - if (*out_fd == -1) - { - _set_error_from_errno (error); - return FALSE; - } - return TRUE; -} - -/** - * gs_file_open_in_tmpdir_at: - * @tmpdir_fd: Directory to place temporary file - * @mode: Default mode (will be affected by umask) - * @out_name: (out) (transfer full): Newly created file name - * @out_stream: (out) (transfer full) (allow-none): Newly created output stream - * @cancellable: - * @error: - * - * Like g_file_open_tmp(), except the file will be created in the - * provided @tmpdir, and allows specification of the Unix @mode, which - * means private files may be created. Return values will be stored - * in @out_name, and optionally @out_stream. - */ -gboolean -gs_file_open_in_tmpdir_at (int tmpdir_fd, - int mode, - char **out_name, - GOutputStream **out_stream, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - const int max_attempts = 128; - int i; - char *tmp_name = NULL; - int fd; - - /* 128 attempts seems reasonable... */ - for (i = 0; i < max_attempts; i++) - { - g_free (tmp_name); - tmp_name = gs_fileutil_gen_tmp_name (NULL, NULL); - - do - fd = openat (tmpdir_fd, tmp_name, O_WRONLY | O_CREAT | O_EXCL, mode); - while (fd == -1 && errno == EINTR); - if (fd < 0 && errno != EEXIST) - { - _set_error_from_errno (error); - goto out; - } - else if (fd != -1) - break; - } - if (i == max_attempts) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Exhausted attempts to open temporary file"); - goto out; - } - - ret = TRUE; - gs_transfer_out_value (out_name, &tmp_name); - if (out_stream) - *out_stream = g_unix_output_stream_new (fd, TRUE); - else - (void) close (fd); - out: - g_free (tmp_name); - return ret; -} - -/** - * gs_file_open_in_tmpdir: - * @tmpdir: Directory to place temporary file - * @mode: Default mode (will be affected by umask) - * @out_file: (out) (transfer full): Newly created file path - * @out_stream: (out) (transfer full) (allow-none): Newly created output stream - * @cancellable: - * @error: - * - * Like g_file_open_tmp(), except the file will be created in the - * provided @tmpdir, and allows specification of the Unix @mode, which - * means private files may be created. Return values will be stored - * in @out_file, and optionally @out_stream. - */ -gboolean -gs_file_open_in_tmpdir (GFile *tmpdir, - int mode, - GFile **out_file, - GOutputStream **out_stream, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - DIR *d = NULL; - int dfd = -1; - char *tmp_name = NULL; - GOutputStream *ret_stream = NULL; - - d = opendir (gs_file_get_path_cached (tmpdir)); - if (!d) - { - _set_error_from_errno (error); - goto out; - } - dfd = dirfd (d); - - if (!gs_file_open_in_tmpdir_at (dfd, mode, &tmp_name, - out_stream ? &ret_stream : NULL, - cancellable, error)) - goto out; - - ret = TRUE; - *out_file = g_file_get_child (tmpdir, tmp_name); - gs_transfer_out_value (out_stream, &ret_stream); - out: - if (d) (void) closedir (d); - g_clear_object (&ret_stream); - g_free (tmp_name); - return ret; -} - -static gboolean -linkcopy_internal_attempt (GFile *src, - GFile *dest, - GFile *dest_parent, - GFileCopyFlags flags, - gboolean sync_data, - gboolean enable_guestfs_fuse_workaround, - gboolean *out_try_again, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int res; - char *tmp_name = NULL; - GFile *tmp_dest = NULL; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto out; - - tmp_name = gs_fileutil_gen_tmp_name (NULL, NULL); - tmp_dest = g_file_get_child (dest_parent, tmp_name); - - res = link (gs_file_get_path_cached (src), gs_file_get_path_cached (tmp_dest)); - if (res == -1) - { - if (errno == EEXIST) - { - /* Nothing, fall through */ - *out_try_again = TRUE; - ret = TRUE; - goto out; - } - else if (errno == EXDEV || errno == EMLINK || errno == EPERM - || (enable_guestfs_fuse_workaround && errno == ENOENT)) - { - if (!g_file_copy (src, tmp_dest, flags, - cancellable, NULL, NULL, error)) - goto out; - } - else - { - _set_error_from_errno (error); - goto out; - } - } - - if (sync_data) - { - /* Now, we need to fsync */ - if (!gs_file_sync_data (tmp_dest, cancellable, error)) - goto out; - } - - if (!gs_file_rename (tmp_dest, dest, cancellable, error)) - goto out; - - ret = TRUE; - *out_try_again = FALSE; - out: - g_clear_pointer (&tmp_name, g_free); - g_clear_object (&tmp_dest); - return ret; -} - -static gboolean -linkcopy_internal (GFile *src, - GFile *dest, - GFileCopyFlags flags, - gboolean sync_data, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - gboolean dest_exists; - int i; - gboolean enable_guestfs_fuse_workaround; - struct stat src_stat; - struct stat dest_stat; - GFile *dest_parent = NULL; - - flags |= G_FILE_COPY_NOFOLLOW_SYMLINKS; - - g_return_val_if_fail ((flags & (G_FILE_COPY_BACKUP | G_FILE_COPY_TARGET_DEFAULT_PERMS)) == 0, FALSE); - - dest_parent = g_file_get_parent (dest); - - if (lstat (gs_file_get_path_cached (src), &src_stat) == -1) - { - int errsv = errno; - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno), - g_strerror (errsv)); - goto out; - } - - if (lstat (gs_file_get_path_cached (dest), &dest_stat) == -1) - dest_exists = FALSE; - else - dest_exists = TRUE; - - if (((flags & G_FILE_COPY_OVERWRITE) == 0) && dest_exists) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_EXISTS, - "File exists"); - goto out; - } - - /* Work around the behavior of link() where it's a no-op if src and - * dest are the same. - */ - if (dest_exists && - src_stat.st_dev == dest_stat.st_dev && - src_stat.st_ino == dest_stat.st_ino) - { - ret = TRUE; - goto out; - } - - enable_guestfs_fuse_workaround = getenv ("LIBGSYSTEM_ENABLE_GUESTFS_FUSE_WORKAROUND") != NULL; - - /* 128 attempts seems reasonable... */ - for (i = 0; i < 128; i++) - { - gboolean tryagain = FALSE; - - if (!linkcopy_internal_attempt (src, dest, dest_parent, - flags, sync_data, - enable_guestfs_fuse_workaround, - &tryagain, - cancellable, error)) - goto out; - - if (!tryagain) - break; - } - - ret = TRUE; - out: - g_clear_object (&dest_parent); - return ret; - -} - -/** - * gs_file_linkcopy: - * @src: Source file - * @dest: Destination file - * @flags: flags - * @cancellable: - * @error: - * - * First tries to use the UNIX link() call, but if the files are on - * separate devices, fall back to copying via g_file_copy(). - * - * The given @flags have different semantics than those documented - * when hardlinking is used. Specifically, both - * #G_FILE_COPY_TARGET_DEFAULT_PERMS and #G_FILE_COPY_BACKUP are not - * supported. #G_FILE_COPY_NOFOLLOW_SYMLINKS treated as if it was - * always given - if you want to follow symbolic links, you will need - * to resolve them manually. - * - * Beware - do not use this function if @src may be modified, and it's - * undesirable for the changes to also be reflected in @dest. The - * best use of this function is in the case where @src and @dest are - * read-only, or where @src is a temporary file, and you want to put - * it in the final place. - */ -gboolean -gs_file_linkcopy (GFile *src, - GFile *dest, - GFileCopyFlags flags, - GCancellable *cancellable, - GError **error) -{ - return linkcopy_internal (src, dest, flags, FALSE, cancellable, error); -} - -/** - * gs_file_linkcopy_sync_data: - * @src: Source file - * @dest: Destination file - * @flags: flags - * @cancellable: - * @error: - * - * This function is similar to gs_file_linkcopy(), except it also uses - * gs_file_sync_data() to ensure that @dest is in stable storage - * before it is moved into place. - */ -gboolean -gs_file_linkcopy_sync_data (GFile *src, - GFile *dest, - GFileCopyFlags flags, - GCancellable *cancellable, - GError **error) -{ - return linkcopy_internal (src, dest, flags, TRUE, cancellable, error); -} - -static char * -gs_file_get_target_path (GFile *file) -{ - GFileInfo *info; - const char *target; - char *path; - - info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, G_FILE_QUERY_INFO_NONE, NULL, NULL); - if (info == NULL) - return NULL; - target = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI); - path = g_filename_from_uri (target, NULL, NULL); - g_object_unref (info); - - return path; -} - -G_LOCK_DEFINE_STATIC (pathname_cache); - -/** - * gs_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 * -gs_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) - { - if (g_file_has_uri_scheme (file, "trash") || - g_file_has_uri_scheme (file, "recent")) - path = gs_file_get_target_path (file); - else - 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; -} - -/** - * gs_file_get_basename_cached: - * - * Like g_file_get_basename(), but returns a constant copy so callers - * don't need to free the result. - */ -const char * -gs_file_get_basename_cached (GFile *file) -{ - const char *name; - static GQuark _file_name_quark = 0; - - if (G_UNLIKELY (_file_name_quark) == 0) - _file_name_quark = g_quark_from_static_string ("gsystem-file-name"); - - G_LOCK (pathname_cache); - - name = g_object_get_qdata ((GObject*)file, _file_name_quark); - if (!name) - { - name = g_file_get_basename (file); - g_object_set_qdata_full ((GObject*)file, _file_name_quark, (char*)name, (GDestroyNotify)g_free); - } - - G_UNLOCK (pathname_cache); - - return name; -} - -/** - * gs_file_enumerator_iterate: - * @direnum: an open #GFileEnumerator - * @out_info: (out) (transfer none) (allow-none): Output location for the next #GFileInfo - * @out_child: (out) (transfer none) (allow-none): Output location for the next #GFile, or %NULL - * @cancellable: a #GCancellable - * @error: a #GError - * - * This is a version of g_file_enumerator_next_file() that's easier to - * use correctly from C programs. With g_file_enumerator_next_file(), - * the gboolean return value signifies "end of iteration or error", which - * requires allocation of a temporary #GError. - * - * In contrast, with this function, a %FALSE return from - * gs_file_enumerator_iterate() <emphasis>always</emphasis> means - * "error". End of iteration is signaled by @out_info being %NULL. - * - * Another crucial difference is that the references for @out_info and - * @out_child are owned by @direnum (they are cached as hidden - * properties). You must not unref them in your own code. This makes - * memory management significantly easier for C code in combination - * with loops. - * - * Finally, this function optionally allows retrieving a #GFile as - * well. - * - * The code pattern for correctly using gs_file_enumerator_iterate() from C - * is: - * - * |[ - * direnum = g_file_enumerate_children (file, ...); - * while (TRUE) - * { - * GFileInfo *info; - * if (!gs_file_enumerator_iterate (direnum, &info, NULL, cancellable, error)) - * goto out; - * if (!info) - * break; - * ... do stuff with "info"; do not unref it! ... - * } - * - * out: - * g_object_unref (direnum); // Note: frees the last @info - * ]| - */ -gboolean -gs_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 ("gsystem-cached-info"); - cached_child_quark = g_quark_from_static_string ("gsystem-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; -} - -/** - * gs_file_rename: - * @from: Current path - * @to: New path - * @cancellable: a #GCancellable - * @error: a #GError - * - * This function wraps the raw Unix function rename(). - * - * Returns: %TRUE on success, %FALSE on error - */ -gboolean -gs_file_rename (GFile *from, - GFile *to, - GCancellable *cancellable, - GError **error) -{ - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - if (rename (gs_file_get_path_cached (from), - gs_file_get_path_cached (to)) < 0) - { - _set_error_from_errno (error); - return FALSE; - } - return TRUE; -} - -/** - * gs_file_unlink: - * @path: Path to file - * @cancellable: a #GCancellable - * @error: a #GError - * - * Like g_file_delete(), except this function does not follow Unix - * symbolic links, and will delete a symbolic link even if it's - * pointing to a nonexistent file. In other words, this function - * merely wraps the raw Unix function unlink(). - * - * Returns: %TRUE on success, %FALSE on error - */ -gboolean -gs_file_unlink (GFile *path, - GCancellable *cancellable, - GError **error) -{ - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - if (unlink (gs_file_get_path_cached (path)) < 0) - { - _set_error_from_errno (error); - return FALSE; - } - return TRUE; -} - -static gboolean -chown_internal (GFile *path, - gboolean dereference_links, - guint32 owner, - guint32 group, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int res; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - do - if (dereference_links) - res = chown (gs_file_get_path_cached (path), owner, group); - else - res = lchown (gs_file_get_path_cached (path), owner, group); - while (G_UNLIKELY (res != 0 && errno == EINTR)); - - if (res < 0) - { - _set_error_from_errno (error); - goto out; - } - - ret = TRUE; - out: - return ret; -} - -/** - * gs_file_chown: - * @path: Path to file - * @owner: UNIX owner - * @group: UNIX group - * @cancellable: a #GCancellable - * @error: a #GError - * - * Merely wraps UNIX chown(). - * - * Returns: %TRUE on success, %FALSE on error - */ -gboolean -gs_file_chown (GFile *path, - guint32 owner, - guint32 group, - GCancellable *cancellable, - GError **error) -{ - return chown_internal (path, TRUE, owner, group, cancellable, error); -} - -/** - * gs_file_lchown: - * @path: Path to file - * @owner: UNIX owner - * @group: UNIX group - * @cancellable: a #GCancellable - * @error: a #GError - * - * Merely wraps UNIX lchown(). - * - * Returns: %TRUE on success, %FALSE on error - */ -gboolean -gs_file_lchown (GFile *path, - guint32 owner, - guint32 group, - GCancellable *cancellable, - GError **error) -{ - return chown_internal (path, FALSE, owner, group, cancellable, error); -} - -/** - * gs_file_chmod: - * @path: Path to file - * @mode: UNIX mode - * @cancellable: a #GCancellable - * @error: a #GError - * - * Merely wraps UNIX chmod(). - * - * Returns: %TRUE on success, %FALSE on error - */ -gboolean -gs_file_chmod (GFile *path, - guint mode, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int res; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - do - res = chmod (gs_file_get_path_cached (path), mode); - while (G_UNLIKELY (res != 0 && errno == EINTR)); - - if (res < 0) - { - _set_error_from_errno (error); - goto out; - } - - ret = TRUE; - out: - return ret; -} - -/** - * gs_file_ensure_directory: - * @dir: Path to create as directory - * @with_parents: Also create parent directories - * @cancellable: a #GCancellable - * @error: a #GError - * - * Like g_file_make_directory(), except does not throw an error if the - * directory already exists. - */ -gboolean -gs_file_ensure_directory (GFile *dir, - gboolean with_parents, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - GError *temp_error = NULL; - GFile *parent = NULL; - - if (!g_file_make_directory (dir, cancellable, &temp_error)) - { - if (with_parents && - g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) - { - g_clear_error (&temp_error); - - parent = g_file_get_parent (dir); - if (parent) - { - if (!gs_file_ensure_directory (parent, TRUE, cancellable, error)) - goto out; - } - if (!gs_file_ensure_directory (dir, FALSE, cancellable, error)) - goto out; - } - else if (!g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS)) - { - g_propagate_error (error, temp_error); - goto out; - } - else - g_clear_error (&temp_error); - } - - ret = TRUE; - out: - g_clear_object (&parent); - return ret; -} - -/** - * gs_file_ensure_directory_mode: - * @dir: Path to create as directory - * @mode: Create directory with these permissions - * @cancellable: a #GCancellable - * @error: a #GError - * - * Wraps UNIX mkdir() function with support for @cancellable, and - * uses @error instead of errno. - */ -gboolean -gs_file_ensure_directory_mode (GFile *dir, - guint mode, - GCancellable *cancellable, - GError **error) -{ - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - if (mkdir (gs_file_get_path_cached (dir), mode) == -1 && errno != EEXIST) - { - _set_error_from_errno (error); - return FALSE; - } - return TRUE; -} - -/** - * gs_file_load_contents_utf8: - * @file: Path to file whose contents must be UTF-8 - * @cancellable: - * @error: - * - * Like g_file_load_contents(), except validates the contents are - * UTF-8. - */ -gchar * -gs_file_load_contents_utf8 (GFile *file, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - gsize len; - char *ret_contents = NULL; - - if (!g_file_load_contents (file, cancellable, &ret_contents, &len, - NULL, error)) - goto out; - if (!g_utf8_validate (ret_contents, len, NULL)) - { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_DATA, - "Invalid UTF-8"); - goto out; - } - - ret = TRUE; - out: - if (!ret) - { - g_free (ret_contents); - return NULL; - } - return ret_contents; -} - -static int -path_common_directory (char *one, - char *two) -{ - int dir_index = 0; - int i = 0; - - while (*one && *two) - { - if (*one != *two) - break; - if (*one == '/') - dir_index = i + 1; - - one++; - two++; - i++; - } - - return dir_index; -} - -/** - * gs_file_get_relpath: - * @one: The first #GFile - * @two: The second #GFile - * - * Like gs_file_get_relative_path(), but does not mandate that - * the two files have any parent in common. This function will - * instead insert "../" where appropriate. - * - * Returns: (transfer full): The relative path between the two. - */ -gchar * -gs_file_get_relpath (GFile *one, - GFile *two) -{ - gchar *simple_path; - gchar *one_path, *one_suffix; - gchar *two_path, *two_suffix; - GString *path; - int i; - - simple_path = g_file_get_relative_path (one, two); - if (simple_path) - return simple_path; - - one_path = g_file_get_path (one); - two_path = g_file_get_path (two); - - i = path_common_directory (one_path, two_path); - one_suffix = one_path + i; - two_suffix = two_path + i; - - path = g_string_new (""); - - /* For every leftover path segment one has, append "../" so - * that we reach the same directory. */ - while (*one_suffix) - { - g_string_append (path, "../"); - one_suffix = strchr (one_suffix, '/'); - if (one_suffix == NULL) - break; - one_suffix++; - } - - /* And now append the leftover stuff on two's side. */ - g_string_append (path, two_suffix); - - g_free (one_path); - g_free (two_path); - - return g_string_free (path, FALSE); -} - -/** - * gs_file_realpath: - * @file: A #GFile - * - * Return a #GFile that contains the same path with symlinks - * followed. That is, it's a #GFile whose path is the result - * of calling realpath() on @file. - * - * Returns: (allow-none) (transfer full): A new #GFile or %NULL if @file is invalid - */ -GFile * -gs_file_realpath (GFile *file) -{ - gchar *path; - gchar path_real[PATH_MAX]; - - path = g_file_get_path (file); - - if (realpath ((const char *) path, path_real) == NULL) - { - g_free (path); - return NULL; - } - - g_free (path); - return g_file_new_for_path (path_real); -} - -#ifdef GSYSTEM_CONFIG_XATTRS -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 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 gboolean -read_xattr_name_array (const char *path, - const char *xattrs, - size_t len, - GVariantBuilder *builder, - GError **error) -{ - gboolean ret = FALSE; - const char *p; - - p = xattrs; - while (p < xattrs+len) - { - ssize_t bytes_read; - char *buf; - GBytes *bytes = NULL; - - bytes_read = lgetxattr (path, p, NULL, 0); - if (bytes_read < 0) - { - _set_error_from_errno (error); - g_prefix_error (error, "lgetxattr (%s, %s) failed: ", path, p); - goto out; - } - if (bytes_read == 0) - continue; - - buf = g_malloc (bytes_read); - bytes = g_bytes_new_take (buf, bytes_read); - if (lgetxattr (path, p, buf, bytes_read) < 0) - { - g_bytes_unref (bytes); - _set_error_from_errno (error); - g_prefix_error (error, "lgetxattr (%s, %s) failed: ", path, p); - goto out; - } - - g_variant_builder_add (builder, "(@ay@ay)", - g_variant_new_bytestring (p), - variant_new_ay_bytes (bytes)); - - p = p + strlen (p) + 1; - g_bytes_unref (bytes); - } - - ret = TRUE; - out: - return ret; -} -#endif - -static gboolean -get_xattrs_impl (GFile *f, - GVariantBuilder *builder, - GCancellable *cancellable, - GError **error) -{ -#ifdef GSYSTEM_CONFIG_XATTRS - gboolean ret = FALSE; - const char *path; - ssize_t bytes_read; - char *xattr_names = NULL; - char *xattr_names_canonical = NULL; - - path = gs_file_get_path_cached (f); - - bytes_read = llistxattr (path, NULL, 0); - - if (bytes_read < 0) - { - if (errno != ENOTSUP) - { - _set_error_from_errno (error); - g_prefix_error (error, "llistxattr (%s) failed: ", path); - goto out; - } - } - else if (bytes_read > 0) - { - xattr_names = g_malloc (bytes_read); - if (llistxattr (path, xattr_names, bytes_read) < 0) - { - _set_error_from_errno (error); - g_prefix_error (error, "llistxattr (%s) failed: ", path); - goto out; - } - xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read); - - if (!read_xattr_name_array (path, xattr_names_canonical, bytes_read, builder, error)) - goto out; - } - - ret = TRUE; - out: - g_clear_pointer (&xattr_names, g_free); - g_clear_pointer (&xattr_names_canonical, g_free); - return ret; -#else - return TRUE; -#endif -} - -/** - * gs_file_get_all_xattrs: - * @f: a #GFile - * @out_xattrs: (out): A new #GVariant containing the extended attributes - * @cancellable: Cancellable - * @error: Error - * - * Read all extended attributes of @f 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 -gs_file_get_all_xattrs (GFile *f, - GVariant **out_xattrs, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - GVariantBuilder builder; - gboolean builder_initialized = FALSE; - GVariant *ret_xattrs = NULL; - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)")); - builder_initialized = TRUE; - - if (!get_xattrs_impl (f, &builder, - cancellable, error)) - goto out; - - ret_xattrs = g_variant_builder_end (&builder); - builder_initialized = FALSE; - g_variant_ref_sink (ret_xattrs); - - ret = TRUE; - gs_transfer_out_value (out_xattrs, &ret_xattrs); - out: - g_clear_pointer (&ret_xattrs, g_variant_unref); - if (!builder_initialized) - g_variant_builder_clear (&builder); - return ret; -} - -/** - * gs_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 -gs_fd_set_all_xattrs (int fd, - GVariant *xattrs, - GCancellable *cancellable, - GError **error) -{ -#ifdef GSYSTEM_CONFIG_XATTRS - gboolean ret = FALSE; - int i, n; - - n = g_variant_n_children (xattrs); - for (i = 0; i < n; i++) - { - const guint8* name; - const guint8* value_data; - GVariant *value = NULL; - gsize value_len; - int res; - - g_variant_get_child (xattrs, i, "(^&ay@ay)", - &name, &value); - value_data = g_variant_get_fixed_array (value, &value_len, 1); - - do - res = fsetxattr (fd, (char*)name, (char*)value_data, value_len, 0); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - g_variant_unref (value); - if (G_UNLIKELY (res == -1)) - { - _set_error_from_errno (error); - goto out; - } - } - - ret = TRUE; - out: - return ret; -#else - return TRUE; -#endif -} - -/** - * gs_file_set_all_xattrs: - * @file: 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 @file. This function does not remove any - * attributes not in @xattrs. - */ -gboolean -gs_file_set_all_xattrs (GFile *file, - GVariant *xattrs, - GCancellable *cancellable, - GError **error) -{ -#ifdef GSYSTEM_CONFIG_XATTRS - gboolean ret = FALSE; - const char *path; - int i, n; - - path = gs_file_get_path_cached (file); - - n = g_variant_n_children (xattrs); - for (i = 0; i < n; i++) - { - const guint8* name; - GVariant *value; - const guint8* value_data; - gsize value_len; - gboolean loop_err; - - g_variant_get_child (xattrs, i, "(^&ay@ay)", - &name, &value); - value_data = g_variant_get_fixed_array (value, &value_len, 1); - - loop_err = lsetxattr (path, (char*)name, (char*)value_data, value_len, 0) < 0; - g_clear_pointer (&value, (GDestroyNotify) g_variant_unref); - if (loop_err) - { - _set_error_from_errno (error); - g_prefix_error (error, "lsetxattr (%s, %s) failed: ", path, name); - goto out; - } - } - - ret = TRUE; - out: - return ret; -#else - return TRUE; -#endif -} diff --git a/libgsystem/gsystem-file-utils.h b/libgsystem/gsystem-file-utils.h deleted file mode 100644 index 021aebb7..00000000 --- a/libgsystem/gsystem-file-utils.h +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 Colin Walters <walters@verbum.org>. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 __GSYSTEM_FILE_UTILS_H__ -#define __GSYSTEM_FILE_UTILS_H__ - -#include <gio/gio.h> -#include <sys/stat.h> - -G_BEGIN_DECLS - -const char *gs_file_get_path_cached (GFile *file); - -const char *gs_file_get_basename_cached (GFile *file); - -gboolean gs_file_enumerator_iterate (GFileEnumerator *direnum, - GFileInfo **out_info, - GFile **out_child, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_openat_noatime (int dfd, - const char *name, - int *ret_fd, - GCancellable *cancellable, - GError **error); - -GInputStream *gs_file_read_noatime (GFile *file, - GCancellable *cancellable, - GError **error); -GMappedFile *gs_file_map_noatime (GFile *file, - GCancellable *cancellable, - GError **error); - -#ifndef __GI_SCANNER__ -gboolean gs_stream_fstat (GFileDescriptorBased *stream, - struct stat *out_stbuf, - GCancellable *cancellable, - GError **error); - -#endif - -#if GLIB_CHECK_VERSION(2,34,0) -GBytes *gs_file_map_readonly (GFile *file, - GCancellable *cancellable, - GError **error); -#endif - -gboolean gs_file_sync_data (GFile *file, - GCancellable *cancellable, - GError **error); - -char * gs_fileutil_gen_tmp_name (const char *prefix, - const char *suffix); - -gboolean gs_file_open_dir_fd (GFile *path, - int *out_fd, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_open_in_tmpdir_at (int tmpdir_fd, - int mode, - char **out_name, - GOutputStream **out_stream, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_open_in_tmpdir (GFile *tmpdir, - int mode, - GFile **out_file, - GOutputStream **out_stream, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_create (GFile *file, - int mode, - GOutputStream **out_stream, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_linkcopy (GFile *src, - GFile *dest, - GFileCopyFlags flags, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_linkcopy_sync_data (GFile *src, - GFile *dest, - GFileCopyFlags flags, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_rename (GFile *from, - GFile *to, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_unlink (GFile *path, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_chown (GFile *path, - guint32 owner, - guint32 group, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_lchown (GFile *path, - guint32 owner, - guint32 group, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_chmod (GFile *path, - guint mode, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_ensure_directory (GFile *dir, - gboolean with_parents, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_ensure_directory_mode (GFile *dir, - guint mode, - GCancellable *cancellable, - GError **error); - -gchar *gs_file_load_contents_utf8 (GFile *file, - GCancellable *cancellable, - GError **error); - -gchar *gs_file_get_relpath (GFile *one, - GFile *two); - -GFile * gs_file_realpath (GFile *file); - -gboolean gs_file_get_all_xattrs (GFile *f, - GVariant **out_xattrs, - GCancellable *cancellable, - GError **error); - -gboolean gs_fd_set_all_xattrs (int fd, - GVariant *xattrs, - GCancellable *cancellable, - GError **error); - -gboolean gs_file_set_all_xattrs (GFile *file, - GVariant *xattrs, - GCancellable *cancellable, - GError **error); - -G_END_DECLS - -#endif diff --git a/libgsystem/gsystem-glib-compat.h b/libgsystem/gsystem-glib-compat.h deleted file mode 100644 index 6fd59c65..00000000 --- a/libgsystem/gsystem-glib-compat.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012,2013 Colin Walters <walters@verbum.org>. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 __LIBGSYSTEM_GLIB_COMPAT__ -#define __LIBGSYSTEM_GLIB_COMPAT__ - -#include <gio/gio.h> - -#if !GLIB_CHECK_VERSION(2,34,0) -static inline void -g_type_ensure (GType type) -{ - if (G_UNLIKELY (type == (GType)-1)) - g_error ("can't happen"); -} - -#define g_clear_pointer(pp, destroy) \ - G_STMT_START { \ - G_STATIC_ASSERT (sizeof *(pp) == sizeof (gpointer)); \ - /* Only one access, please */ \ - gpointer *_pp = (gpointer *) (pp); \ - gpointer _p; \ - /* This assignment is needed to avoid a gcc warning */ \ - GDestroyNotify _destroy = (GDestroyNotify) (destroy); \ - \ - (void) (0 ? (gpointer) *(pp) : 0); \ - do \ - _p = g_atomic_pointer_get (_pp); \ - while G_UNLIKELY (!g_atomic_pointer_compare_and_exchange (_pp, _p, NULL)); \ - \ - if (_p) \ - _destroy (_p); \ - } G_STMT_END - -#endif - -#endif diff --git a/libgsystem/gsystem-local-alloc.c b/libgsystem/gsystem-local-alloc.c deleted file mode 100644 index add3fcb3..00000000 --- a/libgsystem/gsystem-local-alloc.c +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 Colin Walters <walters@verbum.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 "gsystem-local-alloc.h" - -/** - * SECTION:gslocalalloc - * @title: GSystem 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 <ulink - * url="http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html"> - * 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 #gs_free and - * #gs_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 gs_lobj 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 <emphasis>stack - * allocated</emphasis> 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. - * - * <example id="gs-lfree"><title>Calling g_free automatically</title> - * <programlisting> - * - * GFile * - * create_file (GError **error) - * { - * gs_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 - * } - * </programlisting> - * </example> - * - */ diff --git a/libgsystem/gsystem-local-alloc.h b/libgsystem/gsystem-local-alloc.h deleted file mode 100644 index 34db2979..00000000 --- a/libgsystem/gsystem-local-alloc.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 Colin Walters <walters@verbum.org>. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 __GSYSTEM_LOCAL_ALLOC_H__ -#define __GSYSTEM_LOCAL_ALLOC_H__ - -#include <gio/gio.h> - -G_BEGIN_DECLS - -#define GS_DEFINE_CLEANUP_FUNCTION(Type, name, func) \ - static inline void name (void *v) \ - { \ - func (*(Type*)v); \ - } - -#define GS_DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ - static inline void name (void *v) \ - { \ - if (*(Type*)v) \ - func (*(Type*)v); \ - } - -/* These functions shouldn't be invoked directly; - * they are stubs that: - * 1) Take a pointer to the location (typically itself a pointer). - * 2) Provide %NULL-safety where it doesn't exist already (e.g. g_object_unref) - */ -GS_DEFINE_CLEANUP_FUNCTION0(GArray*, gs_local_array_unref, g_array_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GBytes*, gs_local_bytes_unref, g_bytes_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GChecksum*, gs_local_checksum_free, g_checksum_free) -GS_DEFINE_CLEANUP_FUNCTION0(GError*, gs_local_free_error, g_error_free) -GS_DEFINE_CLEANUP_FUNCTION0(GHashTable*, gs_local_hashtable_unref, g_hash_table_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GObject*, gs_local_obj_unref, g_object_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GPtrArray*, gs_local_ptrarray_unref, g_ptr_array_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GVariant*, gs_local_variant_unref, g_variant_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GVariantBuilder*, gs_local_variant_builder_unref, g_variant_builder_unref) -GS_DEFINE_CLEANUP_FUNCTION0(GVariantIter*, gs_local_variant_iter_free, g_variant_iter_free) - -GS_DEFINE_CLEANUP_FUNCTION(char**, gs_local_strfreev, g_strfreev) -GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) - -/** - * gs_free: - * - * Call g_free() on a variable location when it goes out of scope. - */ -#define gs_free __attribute__ ((cleanup(gs_local_free))) - -/** - * gs_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 gs_unref_object __attribute__ ((cleanup(gs_local_obj_unref))) - -/** - * gs_unref_variant: - * - * Call g_variant_unref() on a variable location when it goes out of - * scope. Note that unlike g_variant_unref(), the variable may be - * %NULL. - */ -#define gs_unref_variant __attribute__ ((cleanup(gs_local_variant_unref))) - -/** - * gs_free_variant_iter: - * - * Call g_variant_iter_free() on a variable location when it goes out of - * scope. - */ -#define gs_free_variant_iter __attribute__ ((cleanup(gs_local_variant_iter_free))) - -/** - * gs_free_variant_builder: - * - * Call g_variant_builder_unref() on a variable location when it goes out of - * scope. - */ -#define gs_unref_variant_builder __attribute__ ((cleanup(gs_local_variant_builder_unref))) - -/** - * gs_unref_array: - * - * Call g_array_unref() on a variable location when it goes out of - * scope. Note that unlike g_array_unref(), the variable may be - * %NULL. - - */ -#define gs_unref_array __attribute__ ((cleanup(gs_local_array_unref))) - -/** - * gs_unref_ptrarray: - * - * Call g_ptr_array_unref() on a variable location when it goes out of - * scope. Note that unlike g_ptr_array_unref(), the variable may be - * %NULL. - - */ -#define gs_unref_ptrarray __attribute__ ((cleanup(gs_local_ptrarray_unref))) - -/** - * gs_unref_hashtable: - * - * Call g_hash_table_unref() on a variable location when it goes out - * of scope. Note that unlike g_hash_table_unref(), the variable may - * be %NULL. - */ -#define gs_unref_hashtable __attribute__ ((cleanup(gs_local_hashtable_unref))) - -/** - * gs_free_checksum: - * - * Call g_checksum_free() on a variable location when it goes out - * of scope. Note that unlike g_checksum_free(), the variable may - * be %NULL. - */ -#define gs_free_checksum __attribute__ ((cleanup(gs_local_checksum_free))) - -/** - * gs_unref_bytes: - * - * Call g_bytes_unref() on a variable location when it goes out - * of scope. Note that unlike g_bytes_unref(), the variable may - * be %NULL. - */ -#define gs_unref_bytes __attribute__ ((cleanup(gs_local_bytes_unref))) - -/** - * gs_strfreev: - * - * Call g_strfreev() on a variable location when it goes out of scope. - */ -#define gs_strfreev __attribute__ ((cleanup(gs_local_strfreev))) - -/** - * gs_free_error: - * - * Call g_error_free() on a variable location when it goes out of scope. - */ -#define gs_free_error __attribute__ ((cleanup(gs_local_free_error))) - -G_END_DECLS - -#endif diff --git a/libgsystem/gsystem-log.c b/libgsystem/gsystem-log.c deleted file mode 100644 index 7b031453..00000000 --- a/libgsystem/gsystem-log.c +++ /dev/null @@ -1,167 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 William Jon McCann <mccann@redhat.com> - * Copyright (C) 2012 Colin Walters <walters@verbum.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#ifdef ENABLE_SYSTEMD_JOURNAL -#define SD_JOURNAL_SUPPRESS_LOCATION -#include <systemd/sd-journal.h> -#endif -#include <glib-unix.h> - -#define _GSYSTEM_NO_LOCAL_ALLOC -#include "libgsystem.h" - -/** - * gs_log_structured: - * @message: Text message to send - * @keys: (allow-none) (array zero-terminated=1) (element-type utf8): Optional structured data - * - * Log structured data in an operating-system specific fashion. The - * parameter @opts should be an array of UTF-8 KEY=VALUE strings. - * This function does not support binary data. See - * http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html - * for more information about fields that can be used on a systemd - * system. - */ -void -gs_log_structured (const char *message, - const char *const *keys) -{ -#ifdef ENABLE_SYSTEMD_JOURNAL - const char *const*iter; - char *msgkey; - guint i, n_opts; - struct iovec *iovs; - - for (n_opts = 0, iter = keys; *iter; iter++, n_opts++) - ; - - n_opts++; /* Add one for MESSAGE= */ - iovs = g_alloca (sizeof (struct iovec) * n_opts); - - for (i = 0, iter = keys; *iter; iter++, i++) { - iovs[i].iov_base = (char*)keys[i]; - iovs[i].iov_len = strlen (keys[i]); - } - g_assert(i == n_opts-1); - msgkey = g_strconcat ("MESSAGE=", message, NULL); - iovs[i].iov_base = msgkey; - iovs[i].iov_len = strlen (msgkey); - - // The code location isn't useful since we're wrapping - sd_journal_sendv (iovs, n_opts); - - g_free (msgkey); -#else - g_print ("%s\n", message); -#endif -} - -/** - * gs_stdout_is_journal: - * - * Use this function when you want your code to behave differently - * depeneding on whether your program was started as a systemd unit, - * or e.g. interactively at a terminal. - * - * Returns: %TRUE if stdout is (probably) connnected to the systemd journal - */ -gboolean -gs_stdout_is_journal (void) -{ - static gsize initialized; - static gboolean stdout_is_socket; - - if (g_once_init_enter (&initialized)) - { - guint64 pid = (guint64) getpid (); - char *fdpath = g_strdup_printf ("/proc/%" G_GUINT64_FORMAT "/fd/1", pid); - char buf[1024]; - ssize_t bytes_read; - - if ((bytes_read = readlink (fdpath, buf, sizeof(buf) - 1)) != -1) - { - buf[bytes_read] = '\0'; - stdout_is_socket = g_str_has_prefix (buf, "socket:"); - } - else - stdout_is_socket = FALSE; - - g_free (fdpath); - g_once_init_leave (&initialized, TRUE); - } - - return stdout_is_socket; -} - -/** - * gs_log_structured_print: - * @message: A message to log - * @keys: (allow-none) (array zero-terminated=1) (element-type utf8): Optional structured data - * - * Like gs_log_structured(), but also print to standard output (if it - * is not already connected to the system log). - */ -void -gs_log_structured_print (const char *message, - const char *const *keys) -{ - gs_log_structured (message, keys); - -#ifdef ENABLE_SYSTEMD_JOURNAL - if (!gs_stdout_is_journal ()) - g_print ("%s\n", message); -#endif -} - -/** - * gs_log_structured_print_id_v: - * @message_id: A unique MESSAGE_ID - * @format: A format string - * - * The provided @message_id is a unique MESSAGE_ID (see <ulink url="http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html"> for more information). - * - * This function otherwise acts as gs_log_structured_print(), taking - * @format as a format string. - */ -void -gs_log_structured_print_id_v (const char *message_id, - const char *format, - ...) -{ - char *keys[] = { NULL, NULL }; - char *msg; - va_list args; - - va_start (args, format); - msg = g_strdup_vprintf (format, args); - va_end (args); - - keys[0] = g_strconcat ("MESSAGE_ID=", message_id, NULL); - gs_log_structured_print (msg, (const char *const *)keys); - g_free (keys[0]); - g_free (msg); -} diff --git a/libgsystem/gsystem-log.h b/libgsystem/gsystem-log.h deleted file mode 100644 index 80cfc341..00000000 --- a/libgsystem/gsystem-log.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2013 Colin Walters <walters@verbum.org>. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 __GSYSTEM_LOG_H__ -#define __GSYSTEM_LOG_H__ - -#include <gio/gio.h> - -G_BEGIN_DECLS - -gboolean gs_stdout_is_journal (void); - -void gs_log_structured (const char *message, - const char *const *keys); - -void gs_log_structured_print (const char *message, - const char *const *keys); - -void gs_log_structured_print_id_v (const char *message_id, - const char *format, - ...) G_GNUC_PRINTF (2, 3); - -G_END_DECLS - -#endif diff --git a/libgsystem/gsystem-shutil.c b/libgsystem/gsystem-shutil.c deleted file mode 100644 index 8029dd9c..00000000 --- a/libgsystem/gsystem-shutil.c +++ /dev/null @@ -1,460 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 William Jon McCann <mccann@redhat.com> - * Copyright (C) 2012 Colin Walters <walters@verbum.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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" - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#define _GSYSTEM_NO_LOCAL_ALLOC -#include "libgsystem.h" -#include "gsystem-glib-compat.h" -#include <glib-unix.h> -#include <string.h> -#include <sys/stat.h> -#include <dirent.h> -#include <fcntl.h> - -/* Taken from systemd/src/shared/util.h */ -union dirent_storage { - struct dirent dent; - guint8 storage[offsetof(struct dirent, d_name) + - ((NAME_MAX + 1 + sizeof(long)) & ~(sizeof(long) - 1))]; -}; - -static inline void -_set_error_from_errno (GError **error) -{ - int errsv = errno; - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); -} - -static gboolean -copy_xattrs_from_file_to_fd (GFile *src, - int dest_fd, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - GVariant *src_xattrs = NULL; - - if (!gs_file_get_all_xattrs (src, &src_xattrs, cancellable, error)) - goto out; - - if (src_xattrs) - { - if (!gs_fd_set_all_xattrs (dest_fd, src_xattrs, cancellable, error)) - goto out; - } - - ret = TRUE; - out: - g_clear_pointer (&src_xattrs, g_variant_unref); - return ret; -} - -typedef enum { - GS_CP_MODE_NONE, - GS_CP_MODE_HARDLINK, - GS_CP_MODE_COPY_ALL -} GsCpMode; - -static gboolean -cp_internal (GFile *src, - GFile *dest, - GsCpMode mode, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - GFileEnumerator *enumerator = NULL; - GFileInfo *src_info = NULL; - GFile *dest_child = NULL; - int dest_dfd = -1; - int r; - - enumerator = g_file_enumerate_children (src, "standard::type,standard::name,unix::uid,unix::gid,unix::mode", - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, error); - if (!enumerator) - goto out; - - src_info = g_file_query_info (src, "standard::name,unix::mode,unix::uid,unix::gid," \ - "time::modified,time::modified-usec,time::access,time::access-usec", - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, error); - if (!src_info) - goto out; - - do - r = mkdir (gs_file_get_path_cached (dest), 0755); - while (G_UNLIKELY (r == -1 && errno == EINTR)); - if (r == -1) - { - _set_error_from_errno (error); - goto out; - } - - if (mode != GS_CP_MODE_NONE) - { - if (!gs_file_open_dir_fd (dest, &dest_dfd, - cancellable, error)) - goto out; - - do - r = fchown (dest_dfd, - g_file_info_get_attribute_uint32 (src_info, "unix::uid"), - g_file_info_get_attribute_uint32 (src_info, "unix::gid")); - while (G_UNLIKELY (r == -1 && errno == EINTR)); - if (r == -1) - { - _set_error_from_errno (error); - goto out; - } - - do - r = fchmod (dest_dfd, g_file_info_get_attribute_uint32 (src_info, "unix::mode")); - while (G_UNLIKELY (r == -1 && errno == EINTR)); - - if (!copy_xattrs_from_file_to_fd (src, dest_dfd, cancellable, error)) - goto out; - - if (dest_dfd != -1) - { - (void) close (dest_dfd); - dest_dfd = -1; - } - } - - while (TRUE) - { - GFileInfo *file_info = NULL; - GFile *src_child = NULL; - - if (!gs_file_enumerator_iterate (enumerator, &file_info, &src_child, - cancellable, error)) - goto out; - if (!file_info) - break; - - if (dest_child) g_object_unref (dest_child); - dest_child = g_file_get_child (dest, g_file_info_get_name (file_info)); - - if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) - { - if (!cp_internal (src_child, dest_child, mode, - cancellable, error)) - goto out; - } - else - { - gboolean did_link = FALSE; - (void) unlink (gs_file_get_path_cached (dest_child)); - if (mode == GS_CP_MODE_HARDLINK) - { - if (link (gs_file_get_path_cached (src_child), gs_file_get_path_cached (dest_child)) == -1) - { - if (!(errno == EMLINK || errno == EXDEV)) - { - int errsv = errno; - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); - goto out; - } - /* We failed to hardlink; fall back to copying all; this will - * affect subsequent directory copies too. - */ - mode = GS_CP_MODE_COPY_ALL; - } - else - did_link = TRUE; - } - if (!did_link) - { - GFileCopyFlags copyflags = G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS; - if (mode == GS_CP_MODE_COPY_ALL) - copyflags |= G_FILE_COPY_ALL_METADATA; - if (!g_file_copy (src_child, dest_child, copyflags, - cancellable, NULL, NULL, error)) - goto out; - } - } - } - - ret = TRUE; - out: - if (dest_dfd != -1) - (void) close (dest_dfd); - g_clear_object (&src_info); - g_clear_object (&enumerator); - g_clear_object (&dest_child); - return ret; -} - -/** - * gs_shutil_cp_al_or_fallback: - * @src: Source path - * @dest: Destination path - * @cancellable: - * @error: - * - * Recursively copy path @src (which must be a directory) to the - * target @dest. If possible, hardlinks are used; if a hardlink is - * not possible, a regular copy is created. Any existing files are - * overwritten. - * - * Returns: %TRUE on success - */ -gboolean -gs_shutil_cp_al_or_fallback (GFile *src, - GFile *dest, - GCancellable *cancellable, - GError **error) -{ - return cp_internal (src, dest, GS_CP_MODE_HARDLINK, - cancellable, error); -} - -/** - * gs_shutil_cp_a: - * @src: Source path - * @dest: Destination path - * @cancellable: - * @error: - * - * Recursively copy path @src (which must be a directory) to the - * target @dest. Any existing files are overwritten. - * - * Returns: %TRUE on success - */ -gboolean -gs_shutil_cp_a (GFile *src, - GFile *dest, - GCancellable *cancellable, - GError **error) -{ - return cp_internal (src, dest, GS_CP_MODE_COPY_ALL, - cancellable, error); -} - -static unsigned char -struct_stat_to_dt (struct stat *stbuf) -{ - if (S_ISDIR (stbuf->st_mode)) - return DT_DIR; - if (S_ISREG (stbuf->st_mode)) - return DT_REG; - if (S_ISCHR (stbuf->st_mode)) - return DT_CHR; - if (S_ISBLK (stbuf->st_mode)) - return DT_BLK; - if (S_ISFIFO (stbuf->st_mode)) - return DT_FIFO; - if (S_ISLNK (stbuf->st_mode)) - return DT_LNK; - if (S_ISSOCK (stbuf->st_mode)) - return DT_SOCK; - return DT_UNKNOWN; -} - -static gboolean -gs_shutil_rm_rf_children (DIR *dir, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int dfd; - DIR *child_dir = NULL; - struct dirent *dent; - union dirent_storage buf; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto out; - - dfd = dirfd (dir); - - while (readdir_r (dir, &buf.dent, &dent) == 0) - { - if (dent == NULL) - break; - if (dent->d_type == DT_UNKNOWN) - { - struct stat stbuf; - if (fstatat (dfd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1) - { - int errsv = errno; - if (errsv == ENOENT) - continue; - else - { - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); - goto out; - } - } - dent->d_type = struct_stat_to_dt (&stbuf); - /* Assume unknown types are just treated like regular files */ - if (dent->d_type == DT_UNKNOWN) - dent->d_type = DT_REG; - } - - if (strcmp (dent->d_name, ".") == 0 || strcmp (dent->d_name, "..") == 0) - continue; - - if (dent->d_type == DT_DIR) - { - int child_dfd = openat (dfd, dent->d_name, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); - - if (child_dfd == -1) - { - if (errno == ENOENT) - continue; - else - { - int errsv = errno; - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); - goto out; - } - } - - child_dir = fdopendir (child_dfd); - if (!child_dir) - { - int errsv = errno; - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); - goto out; - } - - if (!gs_shutil_rm_rf_children (child_dir, cancellable, error)) - goto out; - - if (unlinkat (dfd, dent->d_name, AT_REMOVEDIR) == -1) - { - int errsv = errno; - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); - goto out; - } - - (void) closedir (child_dir); - child_dir = NULL; - } - else - { - if (unlinkat (dfd, dent->d_name, 0) == -1) - { - int errsv = errno; - if (errno != ENOENT) - { - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); - goto out; - } - } - } - } - /* Ignore error result from readdir_r, that's what others - * seem to do =( - */ - - ret = TRUE; - out: - if (child_dir) (void) closedir (child_dir); - return ret; -} - -/** - * gs_shutil_rm_rf: - * @path: A file or directory - * @cancellable: - * @error: - * - * Recursively delete the filename referenced by @path; it may be a - * file or directory. No error is thrown if @path does not exist. - */ -gboolean -gs_shutil_rm_rf (GFile *path, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int dfd = -1; - DIR *d = NULL; - - /* With O_NOFOLLOW first */ - dfd = openat (AT_FDCWD, gs_file_get_path_cached (path), - O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); - - if (dfd == -1) - { - int errsv = errno; - if (errsv == ENOENT) - { - ; - } - else if (errsv == ENOTDIR || errsv == ELOOP) - { - if (!gs_file_unlink (path, cancellable, error)) - goto out; - } - else - { - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); - goto out; - } - } - else - { - d = fdopendir (dfd); - if (!d) - { - int errsv = errno; - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); - goto out; - } - - if (!gs_shutil_rm_rf_children (d, cancellable, error)) - goto out; - - if (rmdir (gs_file_get_path_cached (path)) == -1) - { - int errsv = errno; - if (errsv != ENOENT) - { - g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - g_strerror (errsv)); - goto out; - } - } - } - - ret = TRUE; - out: - if (d) (void) closedir (d); - return ret; -} - diff --git a/libgsystem/gsystem-shutil.h b/libgsystem/gsystem-shutil.h deleted file mode 100644 index 3cdea778..00000000 --- a/libgsystem/gsystem-shutil.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 Colin Walters <walters@verbum.org>. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 __GSYSTEM_SHUTIL_H__ -#define __GSYSTEM_SHUTIL_H__ - -#include <gio/gio.h> - -G_BEGIN_DECLS - -gboolean -gs_shutil_cp_al_or_fallback (GFile *src, - GFile *dest, - GCancellable *cancellable, - GError **error); - -gboolean -gs_shutil_cp_a (GFile *src, - GFile *dest, - GCancellable *cancellable, - GError **error); - -gboolean -gs_shutil_rm_rf (GFile *path, - GCancellable *cancellable, - GError **error); - -G_END_DECLS - -#endif diff --git a/libgsystem/gsystem-subprocess-context-private.h b/libgsystem/gsystem-subprocess-context-private.h deleted file mode 100644 index 719df451..00000000 --- a/libgsystem/gsystem-subprocess-context-private.h +++ /dev/null @@ -1,65 +0,0 @@ -/* GIO - GLib Input, Output and Streaming Library - * - * Copyright (C) 2012 Colin Walters <walters@verbum.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public 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 __GS_SUBPROCESS_CONTEXT_PRIVATE_H__ -#define __GS_SUBPROCESS_CONTEXT_PRIVATE_H__ - -#include "gsystem-subprocess-context.h" - -G_BEGIN_DECLS - -struct _GSSubprocessContext -{ - GObject parent; - - GSpawnFlags flags; - gchar **argv; - gboolean has_argv0; - char **envp; - char *cwd; - - GSSubprocessStreamDisposition stdin_disposition; - GSSubprocessStreamDisposition stdout_disposition; - GSSubprocessStreamDisposition stderr_disposition; - - guint keep_descriptors : 1; - guint search_path : 1; - guint search_path_from_envp : 1; - guint unused_flags : 29; - - gint stdin_fd; - gchar *stdin_path; - - gint stdout_fd; - gchar *stdout_path; - - gint stderr_fd; - gchar *stderr_path; - - GArray *postfork_close_fds; - GArray *inherit_fds; - - GSpawnChildSetupFunc child_setup_func; - gpointer child_setup_data; -}; - -G_END_DECLS - -#endif diff --git a/libgsystem/gsystem-subprocess-context.c b/libgsystem/gsystem-subprocess-context.c deleted file mode 100644 index 90ca7167..00000000 --- a/libgsystem/gsystem-subprocess-context.c +++ /dev/null @@ -1,501 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 Colin Walters <walters@verbum.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 "libgsystem.h" - -#if GLIB_CHECK_VERSION(2,34,0) - -#ifdef G_OS_UNIX -#include <gio/gunixoutputstream.h> -#include <gio/gfiledescriptorbased.h> -#include <gio/gunixinputstream.h> -#include <glib-unix.h> -#endif - -/** - * SECTION:gssubprocesscontext - * @title: GSSubprocess Context - * @short_description: Environment options for launching a child process - * - * This class contains a set of options for launching child processes, - * such as where its standard input and output will be directed, the - * argument list, the environment, and more. - * - * While the #GSSubprocess class has high level functions covering - * popular cases, use of this class allows access to more advanced - * options. It can also be used to launch multiple subprocesses with - * a similar configuration. - * - * Since: 2.36 - */ - -#include "config.h" - -#include "gsystem-subprocess-context-private.h" -#include "gsystem-subprocess.h" - -#include <string.h> - -typedef GObjectClass GSSubprocessContextClass; - -G_DEFINE_TYPE (GSSubprocessContext, gs_subprocess_context, G_TYPE_OBJECT); - -enum -{ - PROP_0, - PROP_ARGV, - N_PROPS -}; - -static GParamSpec *gs_subprocess_context_pspecs[N_PROPS]; - -/** - * gs_subprocess_context_new: - * @argv: Argument list - * - * Returns: (transfer full): A new instance of a #GSSubprocessContext. - */ -GSSubprocessContext * -gs_subprocess_context_new (gchar **argv) -{ - g_return_val_if_fail (argv != NULL && argv[0] != NULL, NULL); - - return g_object_new (GS_TYPE_SUBPROCESS_CONTEXT, - "argv", argv, - NULL); -} - -GSSubprocessContext * -gs_subprocess_context_newv (const gchar *first_arg, - ...) -{ - GSSubprocessContext *result; - va_list args; - - g_return_val_if_fail (first_arg != NULL, NULL); - - va_start (args, first_arg); - result = gs_subprocess_context_newa (first_arg, args); - va_end (args); - - return result; -} - -/** - * gs_subprocess_context_newa: - * @first_arg: First argument - * @args: a va_list - * - * Returns: (transfer full): A new instance of a #GSSubprocessContext. - */ -GSSubprocessContext * -gs_subprocess_context_newa (const gchar *first_arg, - va_list args) -{ - GSSubprocessContext *result; - GPtrArray *argv; - - g_return_val_if_fail (first_arg != NULL, NULL); - - argv = g_ptr_array_new (); - do - g_ptr_array_add (argv, (gchar*)first_arg); - while ((first_arg = va_arg (args, const gchar *)) != NULL); - g_ptr_array_add (argv, NULL); - - result = gs_subprocess_context_new ((gchar**)argv->pdata); - - return result; -} - -#ifdef G_OS_UNIX -GSSubprocessContext * -gs_subprocess_context_new_argv0 (const gchar *argv0, - gchar **argv) -{ - GSSubprocessContext *result; - GPtrArray *real_argv; - gchar **iter; - - g_return_val_if_fail (argv0 != NULL, NULL); - g_return_val_if_fail (argv != NULL && argv[0] != NULL, NULL); - - real_argv = g_ptr_array_new (); - g_ptr_array_add (real_argv, (gchar*)argv0); - for (iter = argv; *iter; iter++) - g_ptr_array_add (real_argv, (gchar*) *iter); - g_ptr_array_add (real_argv, NULL); - - result = g_object_new (GS_TYPE_SUBPROCESS_CONTEXT, - "argv", real_argv->pdata, - NULL); - result->has_argv0 = TRUE; - - return result; -} -#endif - -static void -gs_subprocess_context_init (GSSubprocessContext *self) -{ - self->stdin_fd = -1; - self->stdout_fd = -1; - self->stderr_fd = -1; - self->stdout_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT; - self->stderr_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT; - self->postfork_close_fds = g_array_new (FALSE, FALSE, sizeof (int)); - self->inherit_fds = g_array_new (FALSE, FALSE, sizeof (int)); -} - -static void -gs_subprocess_context_finalize (GObject *object) -{ - GSSubprocessContext *self = GS_SUBPROCESS_CONTEXT (object); - - g_strfreev (self->argv); - g_strfreev (self->envp); - g_free (self->cwd); - - g_free (self->stdin_path); - g_free (self->stdout_path); - g_free (self->stderr_path); - - g_array_unref (self->postfork_close_fds); - g_array_unref (self->inherit_fds); - - if (G_OBJECT_CLASS (gs_subprocess_context_parent_class)->finalize != NULL) - G_OBJECT_CLASS (gs_subprocess_context_parent_class)->finalize (object); -} - -static void -gs_subprocess_context_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GSSubprocessContext *self = GS_SUBPROCESS_CONTEXT (object); - - switch (prop_id) - { - case PROP_ARGV: - self->argv = (gchar**) g_value_dup_boxed (value); - break; - - default: - g_assert_not_reached (); - } -} - -static void -gs_subprocess_context_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GSSubprocessContext *self = GS_SUBPROCESS_CONTEXT (object); - - switch (prop_id) - { - case PROP_ARGV: - g_value_set_boxed (value, self->argv); - break; - - default: - g_assert_not_reached (); - } -} - -static void -gs_subprocess_context_class_init (GSSubprocessContextClass *class) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (class); - - gobject_class->finalize = gs_subprocess_context_finalize; - gobject_class->get_property = gs_subprocess_context_get_property; - gobject_class->set_property = gs_subprocess_context_set_property; - - /** - * GSSubprocessContext:argv: - * - * Array of arguments passed to child process; must have at least - * one element. The first element has special handling - if it is - * an not absolute path ( as determined by g_path_is_absolute() ), - * then the system search path will be used. See - * %G_SPAWN_SEARCH_PATH. - * - * Note that in order to use the Unix-specific argv0 functionality, - * you must use the setter function - * gs_subprocess_context_set_args_and_argv0(). For more information - * about this, see %G_SPAWN_FILE_AND_ARGV_ZERO. - * - * Since: 2.36 - */ - gs_subprocess_context_pspecs[PROP_ARGV] = g_param_spec_boxed ("argv", "Arguments", "Arguments for child process", G_TYPE_STRV, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (gobject_class, N_PROPS, gs_subprocess_context_pspecs); -} - -/** - * gs_subprocess_context_argv_append: - * @self: - * @arg: An argument - * - * Append an argument to the child's argument vector. - */ -void -gs_subprocess_context_argv_append (GSSubprocessContext *self, - const gchar *arg) -{ - GPtrArray *new_argv = g_ptr_array_new (); - gchar **iter; - - for (iter = self->argv; *iter; iter++) - g_ptr_array_add (new_argv, *iter); - g_ptr_array_add (new_argv, g_strdup (arg)); - g_ptr_array_add (new_argv, NULL); - - /* Don't free elements */ - g_free (self->argv); - self->argv = (char**)g_ptr_array_free (new_argv, FALSE); -} - -/* Environment */ - -/** - * gs_subprocess_context_set_environment: - * @self: - * @environ: (array zero-terminated=1) (element-type utf8): Environment KEY=VALUE pairs - * - * Replace the environment that will be used for the child process. - * The default is to inherit the current process. - */ -void -gs_subprocess_context_set_environment (GSSubprocessContext *self, - gchar **env) -{ - g_strfreev (self->envp); - self->envp = g_strdupv (env); -} - -void -gs_subprocess_context_set_cwd (GSSubprocessContext *self, - const gchar *cwd) -{ - g_free (self->cwd); - self->cwd = g_strdup (cwd); -} - -void -gs_subprocess_context_set_keep_descriptors (GSSubprocessContext *self, - gboolean keep_descriptors) - -{ - self->keep_descriptors = keep_descriptors ? 1 : 0; -} - -void -gs_subprocess_context_set_search_path (GSSubprocessContext *self, - gboolean search_path, - gboolean search_path_from_envp) -{ - self->search_path = search_path ? 1 : 0; - self->search_path_from_envp = search_path_from_envp ? 1 : 0; -} - -void -gs_subprocess_context_set_stdin_disposition (GSSubprocessContext *self, - GSSubprocessStreamDisposition disposition) -{ - g_return_if_fail (disposition != GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE); - self->stdin_disposition = disposition; -} - -void -gs_subprocess_context_set_stdout_disposition (GSSubprocessContext *self, - GSSubprocessStreamDisposition disposition) -{ - g_return_if_fail (disposition != GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE); - self->stdout_disposition = disposition; -} - -void -gs_subprocess_context_set_stderr_disposition (GSSubprocessContext *self, - GSSubprocessStreamDisposition disposition) -{ - self->stderr_disposition = disposition; -} - -#ifdef G_OS_UNIX -void -gs_subprocess_context_set_stdin_file_path (GSSubprocessContext *self, - const gchar *path) -{ - self->stdin_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL; - g_free (self->stdin_path); - self->stdin_path = g_strdup (path); -} - -void -gs_subprocess_context_set_stdin_fd (GSSubprocessContext *self, - gint fd) -{ - self->stdin_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL; - self->stdin_fd = fd; -} - -void -gs_subprocess_context_set_stdout_file_path (GSSubprocessContext *self, - const gchar *path) -{ - self->stdout_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL; - g_free (self->stdout_path); - self->stdout_path = g_strdup (path); -} - -void -gs_subprocess_context_set_stdout_fd (GSSubprocessContext *self, - gint fd) -{ - self->stdout_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL; - self->stdout_fd = fd; -} - -void -gs_subprocess_context_set_stderr_file_path (GSSubprocessContext *self, - const gchar *path) -{ - self->stderr_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL; - g_free (self->stderr_path); - self->stderr_path = g_strdup (path); -} - -void -gs_subprocess_context_set_stderr_fd (GSSubprocessContext *self, - gint fd) -{ - self->stderr_disposition = GS_SUBPROCESS_STREAM_DISPOSITION_NULL; - self->stderr_fd = fd; -} -#endif - -#ifdef G_OS_UNIX -/** - * gs_subprocess_context_set_child_setup: (skip) - * @self: - * @child_setup: Function to call in the newly forked child, before execve() - * @user_data: Data passed to child - * - * FIXME - note extensive restricitons on GSpawnChildSetupFunc here - */ -void -gs_subprocess_context_set_child_setup (GSSubprocessContext *self, - GSpawnChildSetupFunc child_setup, - gpointer user_data) -{ - self->child_setup_func = child_setup; - self->child_setup_data = user_data; -} - -static gboolean -open_pipe_internal (GSSubprocessContext *self, - gboolean for_read, - void **out_stream, - gint *out_fdno, - GError **error) -{ - int pipefds[2]; - - g_return_val_if_fail (out_stream != NULL, FALSE); - g_return_val_if_fail (out_fdno != NULL, FALSE); - - if (!g_unix_open_pipe (pipefds, FD_CLOEXEC, error)) - return FALSE; - - if (for_read) - { - *out_stream = g_unix_input_stream_new (pipefds[0], TRUE); - *out_fdno = pipefds[1]; - } - else - { - *out_stream = g_unix_output_stream_new (pipefds[1], TRUE); - *out_fdno = pipefds[0]; - } - g_array_append_val (self->inherit_fds, *out_fdno); - g_array_append_val (self->postfork_close_fds, *out_fdno); - - return TRUE; -} - -/** - * gs_subprocess_context_open_pipe_read: - * @self: - * @out_stream: (out) (transfer full): A newly referenced output stream - * @out_fdno: (out): File descriptor number for the subprocess side of the pipe - * - * This allows you to open a pipe between the parent and child - * processes, independent of the standard streams. For this function, - * the pipe is set up so that the parent can read, and the child can - * write. For the opposite version, see - * gs_subprocess_context_open_pipe_write(). - * - * The returned @out_fdno is the file descriptor number that the child - * will see; you need to communicate this number via a separate - * channel, such as the argument list. For example, if you're using - * this pipe to send a password, provide - * <literal>--password-fd=<fdno string></literal>. - * - * Returns: %TRUE on success, %FALSE on error (and @error will be set) - */ -gboolean -gs_subprocess_context_open_pipe_read (GSSubprocessContext *self, - GInputStream **out_stream, - gint *out_fdno, - GError **error) -{ - return open_pipe_internal (self, TRUE, (void**)out_stream, out_fdno, error); -} - -/** - * gs_subprocess_context_open_pipe_write: - * @self: - * @out_stream: (out) (transfer full): A newly referenced stream - * @out_fdno: (out): File descriptor number for the subprocess side of the pipe - * - * Like gs_subprocess_context_open_pipe_read(), but returns a writable - * channel from which the child process can read. - * - * Returns: %TRUE on success, %FALSE on error (and @error will be set) - */ -gboolean -gs_subprocess_context_open_pipe_write (GSSubprocessContext *self, - GOutputStream **out_stream, - gint *out_fdno, - GError **error) -{ - return open_pipe_internal (self, FALSE, (void**)out_stream, out_fdno, error); -} - -#endif - -#endif diff --git a/libgsystem/gsystem-subprocess-context.h b/libgsystem/gsystem-subprocess-context.h deleted file mode 100644 index b8a24012..00000000 --- a/libgsystem/gsystem-subprocess-context.h +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 Colin Walters <walters@verbum.org>. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 __GSYSTEM_SUBPROCESS_CONTEXT_H__ -#define __GSYSTEM_SUBPROCESS_CONTEXT_H__ - -#include <gio/gio.h> - -#if GLIB_CHECK_VERSION(2,34,0) - -G_BEGIN_DECLS - -#define GS_TYPE_SUBPROCESS_CONTEXT (gs_subprocess_context_get_type ()) -#define GS_SUBPROCESS_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_SUBPROCESS_CONTEXT, GSSubprocessContext)) -#define GS_IS_SUBPROCESS_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_SUBPROCESS_CONTEXT)) - -typedef struct _GSSubprocessContext GSSubprocessContext; - -/** - * GSSubprocessStreamDisposition: - * @GS_SUBPROCESS_STREAM_DISPOSITION_NULL: Redirect to operating system's null output stream - * @GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT: Keep the stream from the parent process - * @GS_SUBPROCESS_STREAM_DISPOSITION_PIPE: Open a private unidirectional channel between the processes - * @GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE: Only applicable to standard error; causes it to be merged with standard output - * - * Flags to define the behaviour of the standard input/output/error of - * a #GSSubprocess. - * - * Since: 2.36 - **/ -typedef enum { - GS_SUBPROCESS_STREAM_DISPOSITION_NULL, - GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT, - GS_SUBPROCESS_STREAM_DISPOSITION_PIPE, - GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE -} GSSubprocessStreamDisposition; - -GType gs_subprocess_context_get_type (void) G_GNUC_CONST; - -GSSubprocessContext * gs_subprocess_context_new (gchar **argv); -GSSubprocessContext * gs_subprocess_context_newv (const gchar *first_arg, - ...); -GSSubprocessContext * gs_subprocess_context_newa (const gchar *first_arg, - va_list args); - -#ifdef G_OS_UNIX -GSSubprocessContext * gs_subprocess_context_new_argv0 (const gchar *argv0, - gchar **argv); -#endif - -void gs_subprocess_context_argv_append (GSSubprocessContext *self, - const gchar *arg); - -/* Environment */ - -void gs_subprocess_context_set_environment (GSSubprocessContext *self, - gchar **environ); -void gs_subprocess_context_set_cwd (GSSubprocessContext *self, - const gchar *cwd); -void gs_subprocess_context_set_keep_descriptors (GSSubprocessContext *self, - gboolean keep_descriptors); -void gs_subprocess_context_set_search_path (GSSubprocessContext *self, - gboolean search_path, - gboolean search_path_from_envp); - -/* Basic I/O control */ - -void gs_subprocess_context_set_stdin_disposition (GSSubprocessContext *self, - GSSubprocessStreamDisposition disposition); -void gs_subprocess_context_set_stdout_disposition (GSSubprocessContext *self, - GSSubprocessStreamDisposition disposition); -void gs_subprocess_context_set_stderr_disposition (GSSubprocessContext *self, - GSSubprocessStreamDisposition disposition); - -/* Extended I/O control, only available on UNIX */ - -#ifdef G_OS_UNIX -void gs_subprocess_context_set_stdin_file_path (GSSubprocessContext *self, - const gchar *path); -void gs_subprocess_context_set_stdin_fd (GSSubprocessContext *self, - gint fd); -void gs_subprocess_context_set_stdout_file_path (GSSubprocessContext *self, - const gchar *path); -void gs_subprocess_context_set_stdout_fd (GSSubprocessContext *self, - gint fd); -void gs_subprocess_context_set_stderr_file_path (GSSubprocessContext *self, - const gchar *path); -void gs_subprocess_context_set_stderr_fd (GSSubprocessContext *self, - gint fd); - -gboolean gs_subprocess_context_open_pipe_read (GSSubprocessContext *self, - GInputStream **out_stream, - gint *out_fdno, - GError **error); -gboolean gs_subprocess_context_open_pipe_write (GSSubprocessContext *self, - GOutputStream **out_stream, - gint *out_fdno, - GError **error); -#endif - -/* Child setup, only available on UNIX */ -#ifdef G_OS_UNIX -void gs_subprocess_context_set_child_setup (GSSubprocessContext *self, - GSpawnChildSetupFunc child_setup, - gpointer user_data); -#endif - -G_END_DECLS - -#endif -#endif diff --git a/libgsystem/gsystem-subprocess.c b/libgsystem/gsystem-subprocess.c deleted file mode 100644 index 4ec680f8..00000000 --- a/libgsystem/gsystem-subprocess.c +++ /dev/null @@ -1,966 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* GIO - GLib Input, Output and Streaming Library - * - * Copyright © 2012 Red Hat, Inc. - * Copyright © 2012 Canonical Limited - * - * 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. - * - * See the included COPYING file for more information. - * - * Authors: Colin Walters <walters@verbum.org> - * Ryan Lortie <desrt@desrt.ca> - */ - -#include "config.h" - -#define _GSYSTEM_NO_LOCAL_ALLOC -#include "libgsystem.h" - -#if GLIB_CHECK_VERSION(2,34,0) - -/** - * SECTION:gssubprocess - * @title: GSSubprocess - * @short_description: Create child processes and monitor their status - * - * This class wraps the lower-level g_spawn_async_with_pipes() API, - * providing a more modern GIO-style API, such as returning - * #GInputStream objects for child output pipes. - * - * One major advantage that GIO brings over the core GLib library is - * comprehensive API for asynchronous I/O, such - * g_output_stream_splice_async(). This makes GSubprocess - * significantly more powerful and flexible than equivalent APIs in - * some other languages such as the <literal>subprocess.py</literal> - * included with Python. For example, using #GSubprocess one could - * create two child processes, reading standard output from the first, - * processing it, and writing to the input stream of the second, all - * without blocking the main loop. - * - * Since: 2.36 - */ - -#include "config.h" - -#include "gsystem-subprocess.h" -#include "gsystem-subprocess-context-private.h" - -#include <string.h> -#ifdef G_OS_UNIX -#include <gio/gunixoutputstream.h> -#include <gio/gfiledescriptorbased.h> -#include <gio/gunixinputstream.h> -#include <glib-unix.h> -#endif -#include <fcntl.h> -#ifdef G_OS_WIN32 -#define _WIN32_WINNT 0x0500 -#include <windows.h> -#include "giowin32-priv.h" -#endif - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -static void initable_iface_init (GInitableIface *initable_iface); - -typedef GObjectClass GSSubprocessClass; - -#ifdef G_OS_UNIX -static void -gs_subprocess_unix_queue_waitpid (GSSubprocess *self); -#endif - -struct _GSSubprocess -{ - GObject parent; - - GSSubprocessContext *context; - GPid pid; - - guint pid_valid : 1; - guint reaped_child : 1; - guint unused : 30; - - /* These are the streams created if a pipe is requested via flags. */ - GOutputStream *stdin_pipe; - GInputStream *stdout_pipe; - GInputStream *stderr_pipe; -}; - -G_DEFINE_TYPE_WITH_CODE (GSSubprocess, gs_subprocess, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)); - -enum -{ - PROP_0, - PROP_CONTEXT, - N_PROPS -}; - -static GParamSpec *gs_subprocess_pspecs[N_PROPS]; - -static void -gs_subprocess_init (GSSubprocess *self) -{ -} - -static void -gs_subprocess_finalize (GObject *object) -{ - GSSubprocess *self = GS_SUBPROCESS (object); - - if (self->pid_valid) - { -#ifdef G_OS_UNIX - /* Here we need to actually call waitpid() to clean up the - * zombie. In case the child hasn't actually exited, defer this - * cleanup to the worker thread. - */ - if (!self->reaped_child) - gs_subprocess_unix_queue_waitpid (self); -#endif - g_spawn_close_pid (self->pid); - } - - g_clear_object (&self->stdin_pipe); - g_clear_object (&self->stdout_pipe); - g_clear_object (&self->stderr_pipe); - - if (G_OBJECT_CLASS (gs_subprocess_parent_class)->finalize != NULL) - G_OBJECT_CLASS (gs_subprocess_parent_class)->finalize (object); -} - -static void -gs_subprocess_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GSSubprocess *self = GS_SUBPROCESS (object); - - switch (prop_id) - { - case PROP_CONTEXT: - self->context = g_value_dup_object (value); - break; - - default: - g_assert_not_reached (); - } -} - -static void -gs_subprocess_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GSSubprocess *self = GS_SUBPROCESS (object); - - switch (prop_id) - { - case PROP_CONTEXT: - g_value_set_object (value, self->context); - break; - - default: - g_assert_not_reached (); - } -} - -static void -gs_subprocess_class_init (GSSubprocessClass *class) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (class); - - gobject_class->finalize = gs_subprocess_finalize; - gobject_class->get_property = gs_subprocess_get_property; - gobject_class->set_property = gs_subprocess_set_property; - - /** - * GSSubprocess:context: - * - * - * Since: 2.36 - */ - gs_subprocess_pspecs[PROP_CONTEXT] = g_param_spec_object ("context", "Context", "Subprocess options", GS_TYPE_SUBPROCESS_CONTEXT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (gobject_class, N_PROPS, gs_subprocess_pspecs); -} - -#ifdef G_OS_UNIX - -static gboolean -gs_subprocess_unix_waitpid_dummy (gpointer data) -{ - return FALSE; -} - -static void -gs_subprocess_unix_queue_waitpid (GSSubprocess *self) -{ - GMainContext *worker_context; - GSource *waitpid_source; - -#ifdef GLIB_COMPILATION - worker_context = GLIB_PRIVATE_CALL (g_get_worker_context) (); -#else - worker_context = g_main_context_get_thread_default (); -#endif - waitpid_source = g_child_watch_source_new (self->pid); - g_source_set_callback (waitpid_source, gs_subprocess_unix_waitpid_dummy, NULL, NULL); - g_source_attach (waitpid_source, worker_context); - g_source_unref (waitpid_source); -} - -#endif - -static GInputStream * -platform_input_stream_from_spawn_fd (gint fd) -{ - if (fd < 0) - return NULL; - -#ifdef G_OS_UNIX - return g_unix_input_stream_new (fd, TRUE); -#else - return g_win32_input_stream_new_from_fd (fd, TRUE); -#endif -} - -static GOutputStream * -platform_output_stream_from_spawn_fd (gint fd) -{ - if (fd < 0) - return NULL; - -#ifdef G_OS_UNIX - return g_unix_output_stream_new (fd, TRUE); -#else - return g_win32_output_stream_new_from_fd (fd, TRUE); -#endif -} - -#ifdef G_OS_UNIX -static gint -unix_open_file (const char *filename, - gint mode, - GError **error) -{ - gint my_fd; - - do - my_fd = open (filename, mode | O_BINARY | O_CLOEXEC, 0666); - while (my_fd == -1 && errno == EINTR); - - /* If we return -1 we should also set the error */ - if (my_fd < 0) - { - gint saved_errno = errno; - char *display_name; - - display_name = g_filename_display_name (filename); - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (saved_errno), - "Error opening file '%s': %s", display_name, - g_strerror (saved_errno)); - g_free (display_name); - /* fall through... */ - } - - return my_fd; -} -#endif - -typedef struct -{ - gint fds[3]; - GArray *inherit_fds; - GSpawnChildSetupFunc child_setup_func; - gpointer child_setup_data; -} ChildData; - -static void -child_setup (gpointer user_data) -{ - ChildData *child_data = user_data; - guint i; - gint result; - - /* We're on the child side now. "Rename" the file descriptors in - * child_data.fds[] to stdin/stdout/stderr. - * - * We don't close the originals. It's possible that the originals - * should not be closed and if they should be closed then they should - * have been created O_CLOEXEC. - */ - for (i = 0; i < 3; i++) - { - if (child_data->fds[i] != -1 && child_data->fds[i] != (int) i) - { - do - result = dup2 (child_data->fds[i], i); - while (G_UNLIKELY (result == -1 && errno == EINTR)); - } - } - - /* Unset the CLOEXEC flag for the child *should* inherit */ - for (i = 0; i < child_data->inherit_fds->len; i++) - { - int fd = g_array_index (child_data->inherit_fds, int, i); - int flags; - - do - flags = fcntl (fd, F_GETFL); - while (G_UNLIKELY (flags == -1 && errno == EINTR)); - - flags &= ~FD_CLOEXEC; - - do - result = fcntl (fd, F_SETFD, flags); - while (G_UNLIKELY (result == -1 && errno == EINTR)); - } - - if (child_data->child_setup_func) - child_data->child_setup_func (child_data->child_setup_data); -} - -static gboolean -initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) -{ - GSSubprocess *self = GS_SUBPROCESS (initable); - ChildData child_data = { { -1, -1, -1 } }; - gint *pipe_ptrs[3] = { NULL, NULL, NULL }; - gint pipe_fds[3] = { -1, -1, -1 }; - gint close_fds[3] = { -1, -1, -1 }; - GSpawnFlags spawn_flags = 0; - gboolean success = FALSE; - guint i; - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - /* We must setup the three fds that will end up in the child as stdin, - * stdout and stderr. - * - * First, stdin. - */ -#ifdef G_OS_UNIX - if (self->context->stdin_fd != -1) - child_data.fds[0] = self->context->stdin_fd; - else if (self->context->stdin_path != NULL) - { - child_data.fds[0] = close_fds[0] = unix_open_file (self->context->stdin_path, - O_RDONLY, error); - if (child_data.fds[0] == -1) - goto out; - } - else -#endif - if (self->context->stdin_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_NULL) - ; /* nothing */ - else if (self->context->stdin_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT) - spawn_flags |= G_SPAWN_CHILD_INHERITS_STDIN; - else if (self->context->stdin_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_PIPE) - pipe_ptrs[0] = &pipe_fds[0]; - else - g_assert_not_reached (); - - /* Next, stdout. */ -#ifdef G_OS_UNIX - if (self->context->stdout_fd != -1) - child_data.fds[1] = self->context->stdout_fd; - else if (self->context->stdout_path != NULL) - { - child_data.fds[1] = close_fds[1] = unix_open_file (self->context->stdout_path, - O_CREAT | O_WRONLY, error); - if (child_data.fds[1] == -1) - goto out; - } - else -#endif - if (self->context->stdout_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_NULL) - spawn_flags |= G_SPAWN_STDOUT_TO_DEV_NULL; - else if (self->context->stdout_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT) - ; /* Nothing */ - else if (self->context->stdout_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_PIPE) - pipe_ptrs[1] = &pipe_fds[1]; - else - g_assert_not_reached (); - - /* Finally, stderr. */ -#ifdef G_OS_UNIX - if (self->context->stderr_fd != -1) - child_data.fds[2] = self->context->stderr_fd; - else if (self->context->stderr_path != NULL) - { - child_data.fds[2] = close_fds[2] = unix_open_file (self->context->stderr_path, - O_CREAT | O_WRONLY, error); - if (child_data.fds[2] == -1) - goto out; - } - else -#endif - if (self->context->stderr_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_NULL) - spawn_flags |= G_SPAWN_STDERR_TO_DEV_NULL; - else if (self->context->stderr_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT) - ; /* Nothing */ - else if (self->context->stderr_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_PIPE) - pipe_ptrs[2] = &pipe_fds[2]; - else if (self->context->stderr_disposition == GS_SUBPROCESS_STREAM_DISPOSITION_STDERR_MERGE) - /* This will work because stderr gets setup after stdout. */ - child_data.fds[2] = 1; - else - g_assert_not_reached (); - - child_data.inherit_fds = self->context->inherit_fds; - - if (self->context->keep_descriptors) - spawn_flags |= G_SPAWN_LEAVE_DESCRIPTORS_OPEN; - - if (self->context->search_path) - spawn_flags |= G_SPAWN_SEARCH_PATH; - else if (self->context->search_path_from_envp) - spawn_flags |= G_SPAWN_SEARCH_PATH_FROM_ENVP; - else if (!g_path_is_absolute (((gchar**)self->context->argv)[0])) - spawn_flags |= G_SPAWN_SEARCH_PATH; - - if (self->context->has_argv0) - spawn_flags |= G_SPAWN_FILE_AND_ARGV_ZERO; - - spawn_flags |= G_SPAWN_DO_NOT_REAP_CHILD; -#ifdef GLIB_COMPILATION - spawn_flags |= G_SPAWN_CLOEXEC_PIPES; -#endif - - child_data.child_setup_func = self->context->child_setup_func; - child_data.child_setup_data = self->context->child_setup_data; - success = g_spawn_async_with_pipes (self->context->cwd, - (char**)self->context->argv, - self->context->envp, - spawn_flags, - child_setup, &child_data, - &self->pid, - pipe_ptrs[0], pipe_ptrs[1], pipe_ptrs[2], - error); - if (success) - self->pid_valid = TRUE; - -out: - for (i = 0; i < 3; i++) - if (close_fds[i] != -1) - close (close_fds[i]); - - for (i = 0; i < self->context->postfork_close_fds->len; i++) - (void) close (g_array_index (self->context->postfork_close_fds, int, i)); - - self->stdin_pipe = platform_output_stream_from_spawn_fd (pipe_fds[0]); - self->stdout_pipe = platform_input_stream_from_spawn_fd (pipe_fds[1]); - self->stderr_pipe = platform_input_stream_from_spawn_fd (pipe_fds[2]); - - return success; -} - -static void -initable_iface_init (GInitableIface *initable_iface) -{ - initable_iface->init = initable_init; -} - -/** - * gs_subprocess_new: - * - * Create a new process, using the parameters specified by - * GSSubprocessContext. - * - * Returns: (transfer full): A newly created %GSSubprocess, or %NULL on error (and @error will be set) - * - * Since: 2.36 - */ -GSSubprocess * -gs_subprocess_new (GSSubprocessContext *context, - GCancellable *cancellable, - GError **error) -{ - return g_initable_new (GS_TYPE_SUBPROCESS, - cancellable, error, - "context", context, - NULL); -} - -/** - * gs_subprocess_get_pid: - * @self: a #GSSubprocess - * - * The identifier for this child process; it is valid as long as the - * process @self is referenced. In particular, do - * <emphasis>not</emphasis> call g_spawn_close_pid() on this value; - * that is handled internally. - * - * On some Unix versions, it is possible for there to be a race - * condition where waitpid() may have been called to collect the child - * before any watches (such as that installed by - * gs_subprocess_add_watch()) have fired. If you are planning to use - * native functions such as kill() on the pid, your program should - * gracefully handle an %ESRCH result to mitigate this. - * - * If you want to request process termination, using the high level - * gs_subprocess_request_exit() and gs_subprocess_force_exit() API is - * recommended. - * - * Returns: Operating-system specific identifier for child process - * - * Since: 2.36 - */ -GPid -gs_subprocess_get_pid (GSSubprocess *self) -{ - g_return_val_if_fail (GS_IS_SUBPROCESS (self), 0); - - return self->pid; -} - -/** - * gs_subprocess_get_stdin_pipe: - * - * Returns: (transfer none): Pipe - */ -GOutputStream * -gs_subprocess_get_stdin_pipe (GSSubprocess *self) -{ - g_return_val_if_fail (GS_IS_SUBPROCESS (self), NULL); - g_return_val_if_fail (self->stdin_pipe, NULL); - - return self->stdin_pipe; -} - -/** - * gs_subprocess_get_stdout_pipe: - * - * Returns: (transfer none): Pipe - */ -GInputStream * -gs_subprocess_get_stdout_pipe (GSSubprocess *self) -{ - g_return_val_if_fail (GS_IS_SUBPROCESS (self), NULL); - g_return_val_if_fail (self->stdout_pipe, NULL); - - return self->stdout_pipe; -} - -/** - * gs_subprocess_get_stderr_pipe: - * - * Returns: (transfer none): Pipe - */ -GInputStream * -gs_subprocess_get_stderr_pipe (GSSubprocess *self) -{ - g_return_val_if_fail (GS_IS_SUBPROCESS (self), NULL); - g_return_val_if_fail (self->stderr_pipe, NULL); - - return self->stderr_pipe; -} - -typedef struct { - GSSubprocess *self; - GCancellable *cancellable; - GSimpleAsyncResult *result; -} GSSubprocessWatchData; - -static gboolean -gs_subprocess_on_child_exited (GPid pid, - gint status_code, - gpointer user_data) -{ - GSSubprocessWatchData *data = user_data; - GError *error = NULL; - - if (g_cancellable_set_error_if_cancelled (data->cancellable, &error)) - { - g_simple_async_result_take_error (data->result, error); - } - else - { - data->self->reaped_child = TRUE; - - g_simple_async_result_set_op_res_gssize (data->result, status_code); - } - - g_simple_async_result_complete (data->result); - - g_object_unref (data->result); - g_object_unref (data->self); - g_free (data); - - return FALSE; -} - -/** - * gs_subprocess_wait: - * @self: a #GSSubprocess - * @cancellable: a #GCancellable - * @callback: Invoked when process exits, or @cancellable is cancelled - * @user_data: Data for @callback - * - * Start an asynchronous wait for the subprocess @self to exit. - * - * Since: 2.36 - */ -void -gs_subprocess_wait (GSSubprocess *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSource *source; - GSSubprocessWatchData *data; - - data = g_new0 (GSSubprocessWatchData, 1); - - data->self = g_object_ref (self); - data->result = g_simple_async_result_new ((GObject*)self, callback, user_data, - gs_subprocess_wait); - - source = g_child_watch_source_new (self->pid); - - g_source_set_callback (source, (GSourceFunc)gs_subprocess_on_child_exited, - data, NULL); - if (cancellable) - { - GSource *cancellable_source; - - data->cancellable = g_object_ref (cancellable); - - cancellable_source = g_cancellable_source_new (cancellable); - g_source_add_child_source (source, cancellable_source); - g_source_unref (cancellable_source); - } - - g_source_attach (source, g_main_context_get_thread_default ()); - g_source_unref (source); -} - -/** - * gs_subprocess_wait_finish: - * @self: a #GSSubprocess - * @result: a #GAsyncResult - * @out_exit_status: (out): Exit status of the process encoded in platform-specific way - * @error: a #GError - * - * The exit status of the process will be stored in @out_exit_status. - * See the documentation of g_spawn_check_exit_status() for more - * details. - * - * Note that @error is not set if the process exits abnormally; you - * must use g_spawn_check_exit_status() for that. - * - * Since: 2.36 - */ -gboolean -gs_subprocess_wait_finish (GSSubprocess *self, - GAsyncResult *result, - int *out_exit_status, - GError **error) -{ - GSimpleAsyncResult *simple; - - simple = G_SIMPLE_ASYNC_RESULT (result); - - if (g_simple_async_result_propagate_error (simple, error)) - return FALSE; - - *out_exit_status = g_simple_async_result_get_op_res_gssize (simple); - - return TRUE; -} - -typedef struct { - GMainLoop *loop; - gint *exit_status_ptr; - gboolean caught_error; - GError **error; -} GSSubprocessSyncWaitData; - -static void -gs_subprocess_on_sync_wait_complete (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - GSSubprocessSyncWaitData *data = user_data; - - if (!gs_subprocess_wait_finish ((GSSubprocess*)object, result, - data->exit_status_ptr, data->error)) - data->caught_error = TRUE; - - g_main_loop_quit (data->loop); -} - -/** - * gs_subprocess_wait_sync: - * @self: a #GSSubprocess - * @out_exit_status: (out): Platform-specific exit code - * @cancellable: a #GCancellable - * @error: a #GError - * - * Synchronously wait for the subprocess to terminate, returning the - * status code in @out_exit_status. See the documentation of - * g_spawn_check_exit_status() for how to interpret it. Note that if - * @error is set, then @out_exit_status will be left uninitialized. - * - * Returns: %TRUE on success, %FALSE if @cancellable was cancelled - * - * Since: 2.36 - */ -gboolean -gs_subprocess_wait_sync (GSSubprocess *self, - int *out_exit_status, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - gboolean pushed_thread_default = FALSE; - GMainContext *context = NULL; - GSSubprocessSyncWaitData data; - - memset (&data, 0, sizeof (data)); - - g_return_val_if_fail (GS_IS_SUBPROCESS (self), FALSE); - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return FALSE; - - context = g_main_context_new (); - g_main_context_push_thread_default (context); - pushed_thread_default = TRUE; - - data.exit_status_ptr = out_exit_status; - data.loop = g_main_loop_new (context, TRUE); - data.error = error; - - gs_subprocess_wait (self, cancellable, - gs_subprocess_on_sync_wait_complete, &data); - - g_main_loop_run (data.loop); - - if (data.caught_error) - goto out; - - ret = TRUE; - out: - if (pushed_thread_default) - g_main_context_pop_thread_default (context); - if (context) - g_main_context_unref (context); - if (data.loop) - g_main_loop_unref (data.loop); - - return ret; -} - -/** - * gs_subprocess_wait_sync_check: - * @self: a #GSSubprocess - * @cancellable: a #GCancellable - * @error: a #GError - * - * Combines gs_subprocess_wait_sync() with g_spawn_check_exit_status(). - * - * Returns: %TRUE on success, %FALSE if process exited abnormally, or @cancellable was cancelled - * - * Since: 2.36 - */ -gboolean -gs_subprocess_wait_sync_check (GSSubprocess *self, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int exit_status; - - if (!gs_subprocess_wait_sync (self, &exit_status, cancellable, error)) - goto out; - - if (!g_spawn_check_exit_status (exit_status, error)) - goto out; - - ret = TRUE; - out: - return ret; -} - -/** - * gs_subprocess_request_exit: - * @self: a #GSSubprocess - * - * This API uses an operating-system specific mechanism to request - * that the subprocess gracefully exit. This API is not available on - * all operating systems; for those not supported, it will do nothing - * and return %FALSE. Portable code should handle this situation - * gracefully. For example, if you are communicating via input or - * output pipe with the child, many programs will automatically exit - * when one of their standard input or output are closed. - * - * On Unix, this API sends %SIGTERM. - * - * A %TRUE return value does <emphasis>not</emphasis> mean the - * subprocess has exited, merely that an exit request was initiated. - * You can use gs_subprocess_add_watch() to monitor the status of the - * process after calling this function. - * - * This function returns %TRUE if the process has already exited. - * - * Returns: %TRUE if the operation is supported, %FALSE otherwise. - * - * Since: 2.36 - */ -gboolean -gs_subprocess_request_exit (GSSubprocess *self) -{ - g_return_val_if_fail (GS_IS_SUBPROCESS (self), FALSE); - -#ifdef G_OS_UNIX - (void) kill (self->pid, SIGTERM); - return TRUE; -#else - return FALSE; -#endif -} - -/** - * gs_subprocess_force_exit: - * @self: a #GSSubprocess - * - * Use an operating-system specific method to attempt an immediate, - * forceful termination of the process. There is no mechanism to - * determine whether or not the request itself was successful; - * however, you can use gs_subprocess_wait() to monitor the status of - * the process after calling this function. - * - * On Unix, this function sends %SIGKILL. - */ -void -gs_subprocess_force_exit (GSSubprocess *self) -{ - g_return_if_fail (GS_IS_SUBPROCESS (self)); - -#if !defined(GLIB_COMPIATION) - { - int ret; - do - ret = kill (self->pid, SIGKILL); - while (ret == -1 && errno == EINTR); - } -#elif defined(G_OS_UNIX) - GLIB_PRIVATE_CALL (g_main_send_signal) (self->pid, SIGKILL); -#else - TerminateProcess (self->pid, 1); -#endif -} - -GSSubprocess * -gs_subprocess_new_simple_argl (GSSubprocessStreamDisposition stdout_disposition, - GSSubprocessStreamDisposition stderr_disposition, - GCancellable *cancellable, - GError **error, - const gchar *first_arg, - ...) -{ - va_list args; - GSSubprocess *result; - GSSubprocessContext *context; - - va_start (args, first_arg); - context = gs_subprocess_context_newa (first_arg, args); - va_end (args); - result = gs_subprocess_new (context, cancellable, error); - g_object_unref (context); - - return result; -} - -/** - * gs_subprocess_new_simple_argv: - * @argv: (array zero-terminated=1) (element-type utf8): Argument array - * @stdout_disposition: Where to redirect stdout - * @stderr_disposition: Where to redirect stdout - * @error: a #GError - * - * Create a new subprocess using the provided argument array and - * stream dispositions. - */ -GSSubprocess * -gs_subprocess_new_simple_argv (gchar **argv, - GSSubprocessStreamDisposition stdout_disposition, - GSSubprocessStreamDisposition stderr_disposition, - GCancellable *cancellable, - GError **error) -{ - GSSubprocessContext *context; - GSSubprocess *result; - - context = gs_subprocess_context_new (argv); - gs_subprocess_context_set_stdout_disposition (context, stdout_disposition); - gs_subprocess_context_set_stderr_disposition (context, stderr_disposition); - - result = gs_subprocess_new (context, cancellable, error); - g_object_unref (context); - - return result; -} - -/** - * gs_subprocess_simple_run_sync: - * @cwd: Current working directory - * @stdin_disposition: What to do with standard input - * @cancellable: a #GCancellable - * @error: a #GError - * @first_arg: First argument - * @...: Remaining arguments, %NULL terminated - * - * Run a process synchronously, throw an error if it fails. - */ -gboolean -gs_subprocess_simple_run_sync (const char *cwd, - GSSubprocessStreamDisposition stdin_disposition, - GCancellable *cancellable, - GError **error, - const char *first_arg, - ...) -{ - gboolean ret = FALSE; - va_list args; - GSSubprocess *proc = NULL; - GSSubprocessContext *context = NULL; - - va_start (args, first_arg); - context = gs_subprocess_context_newa (first_arg, args); - va_end (args); - gs_subprocess_context_set_stdin_disposition (context, stdin_disposition); - gs_subprocess_context_set_cwd (context, cwd); - proc = gs_subprocess_new (context, cancellable, error); - if (!proc) - goto out; - - if (!gs_subprocess_wait_sync_check (proc, cancellable, error)) - goto out; - - ret = TRUE; - out: - g_object_unref (context); - if (proc) - g_object_unref (proc); - return ret; -} - -#endif diff --git a/libgsystem/gsystem-subprocess.h b/libgsystem/gsystem-subprocess.h deleted file mode 100644 index f248f7ba..00000000 --- a/libgsystem/gsystem-subprocess.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012 Colin Walters <walters@verbum.org>. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 __GSYSTEM_SUBPROCESS_H__ -#define __GSYSTEM_SUBPROCESS_H__ - -#include <gio/gio.h> - -#if GLIB_CHECK_VERSION(2,34,0) - -#include "gsystem-subprocess-context.h" - -G_BEGIN_DECLS - -#define GS_TYPE_SUBPROCESS (gs_subprocess_get_type ()) -#define GS_SUBPROCESS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_SUBPROCESS, GSSubprocess)) -#define GS_IS_SUBPROCESS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_SUBPROCESS)) - -typedef struct _GSSubprocess GSSubprocess; - -GType gs_subprocess_get_type (void) G_GNUC_CONST; - -/**** Core API ****/ - -GSSubprocess * gs_subprocess_new (GSSubprocessContext *context, - GCancellable *cancellable, - GError **error); - -GOutputStream * gs_subprocess_get_stdin_pipe (GSSubprocess *self); - -GInputStream * gs_subprocess_get_stdout_pipe (GSSubprocess *self); - -GInputStream * gs_subprocess_get_stderr_pipe (GSSubprocess *self); - -void gs_subprocess_wait (GSSubprocess *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean gs_subprocess_wait_finish (GSSubprocess *self, - GAsyncResult *result, - int *out_exit_status, - GError **error); - -gboolean gs_subprocess_wait_sync (GSSubprocess *self, - int *out_exit_status, - GCancellable *cancellable, - GError **error); - -gboolean gs_subprocess_wait_sync_check (GSSubprocess *self, - GCancellable *cancellable, - GError **error); - -GPid gs_subprocess_get_pid (GSSubprocess *self); - -gboolean gs_subprocess_request_exit (GSSubprocess *self); - -void gs_subprocess_force_exit (GSSubprocess *self); - -/**** High level helpers ****/ - -GSSubprocess * gs_subprocess_new_simple_argl (GSSubprocessStreamDisposition stdout_disposition, - GSSubprocessStreamDisposition stderr_disposition, - GCancellable *cancellable, - GError **error, - const char *first_arg, - ...) G_GNUC_NULL_TERMINATED; -GSSubprocess * gs_subprocess_new_simple_argv (char **argv, - GSSubprocessStreamDisposition stdout_disposition, - GSSubprocessStreamDisposition stderr_disposition, - GCancellable *cancellable, - GError **error); - -gboolean gs_subprocess_simple_run_sync (const char *cwd, - GSSubprocessStreamDisposition stdin_disposition, - GCancellable *cancellable, - GError **error, - const char *first_arg, - ...) G_GNUC_NULL_TERMINATED; - -G_END_DECLS - -#endif -#endif diff --git a/libgsystem/libgsystem.h b/libgsystem/libgsystem.h deleted file mode 100644 index 60884b65..00000000 --- a/libgsystem/libgsystem.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2012,2013 Colin Walters <walters@verbum.org>. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * 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 __LIBGSYSTEM__ -#define __LIBGSYSTEM__ - -#include <gio/gio.h> - -G_BEGIN_DECLS - -#define gs_transfer_out_value(outp, srcp) G_STMT_START { \ - if (outp) \ - { \ - *(outp) = *(srcp); \ - *(srcp) = NULL; \ - } \ - } G_STMT_END; - -#include <gsystem-console.h> -#include <gsystem-file-utils.h> -#include <gsystem-shutil.h> -#if GLIB_CHECK_VERSION(2,34,0) -#include <gsystem-subprocess.h> -#endif -#include <gsystem-log.h> -#ifndef _GSYSTEM_NO_LOCAL_ALLOC -#include <gsystem-local-alloc.h> -#endif - -G_END_DECLS - -#endif |